About this skill
This skill provides an AI agent with the knowledge and patterns to implement effective testing strategies for Perl applications. It covers a broad spectrum of modern Perl testing tools and practices, including the use of `Test2::V0` for contemporary testing, `Test::More` for broader compatibility, the `prove` runner for executing test suites, and techniques for mocking dependencies. The skill also integrates `Devel::Cover` for assessing code coverage and emphasizes a disciplined Test-Driven Development (TDD) workflow (Red-Green-Refactor) to ensure high-quality, maintainable, and robust Perl code from inception. It's designed to help agents not only write tests but also design comprehensive test suites, review coverage, set up testing infrastructure, and debug issues.
Best use case
Ensuring the quality and reliability of new and existing Perl codebases. Implementing a robust testing strategy for Perl modules, scripts, or applications. Adhering to Test-Driven Development (TDD) principles in Perl development. Setting up and configuring a Perl testing environment. Migrating existing Perl tests to modern frameworks like Test2::V0. Debugging and resolving issues in Perl test suites.
使用Test2::V0、Test::More、prove runner、模拟、Devel::Cover覆盖率和TDD方法的Perl测试模式。
Well-structured and comprehensive Perl test files (`.t` files) using `Test2::V0` or `Test::More`. Perl application code developed following the Test-Driven Development (TDD) cycle, ensuring high test coverage and correctness. Suggestions for setting up `prove` as a test runner and integrating `Devel::Cover` for coverage reports. Robust Perl code that demonstrates proper error handling, edge case considerations, and maintainability. Guidance on mocking dependencies for unit tests.
Practical example
Example input
Help me develop a new Perl module named `Calculator` that performs basic arithmetic. I want to follow TDD principles and use `Test2::V0` for testing. Start with the `add` method.
Example output
# Step 1: RED — Write a failing test
# t/unit/calculator.t
use v5.36;
use Test2::V0;
# Assuming lib/Calculator.pm will be created
use lib 'lib';
use Calculator;
subtest 'addition' => sub {
my $calc = Calculator->new;
is($calc->add(2, 3), 5, 'adds two numbers');
is($calc->add(-1, 1), 0, 'handles negatives');
# Add more test cases for edge scenarios if applicable
};
done_testing;
# Explanation: This test will fail initially because Calculator.pm
# and the add method do not yet exist.
# Step 2: GREEN — Write minimal implementation to make tests pass
# lib/Calculator.pm
package Calculator;
use v5.36;
use Moo; # Or any preferred OOP framework like Class::Accessor, Moose, etc.
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub add {
my ($self, $a, $b) = @_;
return $a + $b;
}
1; # End of module
# Explanation: Now, running `prove -lv t/unit/calculator.t` should
# result in all tests passing.
# Step 3: REFACTOR — Improve code structure, readability, performance (if needed)
# (Agent would suggest refactoring if the implementation was complex or inefficient)
# No refactoring needed for simple addition, but for more complex logic,
# this step would involve improving the code without changing its external behavior,
# e.g., optimizing algorithms, improving variable names, etc.
# Continue the cycle for other methods like subtract, multiply, divide.When to use this skill
- When writing new Perl code and intending to follow a Test-Driven Development (TDD) approach (Red, Green, Refactor cycle).
- When designing or extending a test suite for a Perl module or application.
- When reviewing the test coverage of existing Perl code to identify untested areas.
- When tasked with setting up or improving the testing infrastructure for a Perl project.
When not to use this skill
- When working with programming languages other than Perl.
- When the task does not involve code testing or quality assurance (e.g., pure code generation without testing requirements).
- When an existing, well-established testing framework is already in place and does not require modification or adherence to these specific patterns.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/perl-testing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How perl-testing Compares
| Feature / Agent | perl-testing | Standard Approach |
|---|---|---|
| Platform Support | Claude | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | easy | N/A |
Frequently Asked Questions
What does this skill do?
使用Test2::V0、Test::More、prove runner、模拟、Devel::Cover覆盖率和TDD方法的Perl测试模式。
Which AI agents support this skill?
This skill is designed for Claude.
How difficult is it to install?
The installation complexity is rated as easy. You can find the installation instructions above.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
AI Agents for Coding
Browse AI agent skills for coding, debugging, testing, refactoring, code review, and developer workflows across Claude, Cursor, and Codex.
Best AI Skills for Claude
Explore the best AI skills for Claude and Claude Code across coding, research, workflow automation, documentation, and agent operations.
ChatGPT vs Claude for Agent Skills
Compare ChatGPT and Claude for AI agent skills across coding, writing, research, and reusable workflow execution.
SKILL.md Source
# Perl 测试模式
使用 Test2::V0、Test::More、prove 和 TDD 方法论为 Perl 应用程序提供全面的测试策略。
## 何时激活
* 编写新的 Perl 代码(遵循 TDD:红、绿、重构)
* 为 Perl 模块或应用程序设计测试套件
* 审查 Perl 测试覆盖率
* 设置 Perl 测试基础设施
* 将测试从 Test::More 迁移到 Test2::V0
* 调试失败的 Perl 测试
## TDD 工作流程
始终遵循 RED-GREEN-REFACTOR 循环。
```perl
# Step 1: RED — Write a failing test
# t/unit/calculator.t
use v5.36;
use Test2::V0;
use lib 'lib';
use Calculator;
subtest 'addition' => sub {
my $calc = Calculator->new;
is($calc->add(2, 3), 5, 'adds two numbers');
is($calc->add(-1, 1), 0, 'handles negatives');
};
done_testing;
# Step 2: GREEN — Write minimal implementation
# lib/Calculator.pm
package Calculator;
use v5.36;
use Moo;
sub add($self, $a, $b) {
return $a + $b;
}
1;
# Step 3: REFACTOR — Improve while tests stay green
# Run: prove -lv t/unit/calculator.t
```
## Test::More 基础
标准的 Perl 测试模块 —— 广泛使用,随核心发行。
### 基本断言
```perl
use v5.36;
use Test::More;
# Plan upfront or use done_testing
# plan tests => 5; # Fixed plan (optional)
# Equality
is($result, 42, 'returns correct value');
isnt($result, 0, 'not zero');
# Boolean
ok($user->is_active, 'user is active');
ok(!$user->is_banned, 'user is not banned');
# Deep comparison
is_deeply(
$got,
{ name => 'Alice', roles => ['admin'] },
'returns expected structure'
);
# Pattern matching
like($error, qr/not found/i, 'error mentions not found');
unlike($output, qr/password/, 'output hides password');
# Type check
isa_ok($obj, 'MyApp::User');
can_ok($obj, 'save', 'delete');
done_testing;
```
### SKIP 和 TODO
```perl
use v5.36;
use Test::More;
# Skip tests conditionally
SKIP: {
skip 'No database configured', 2 unless $ENV{TEST_DB};
my $db = connect_db();
ok($db->ping, 'database is reachable');
is($db->version, '15', 'correct PostgreSQL version');
}
# Mark expected failures
TODO: {
local $TODO = 'Caching not yet implemented';
is($cache->get('key'), 'value', 'cache returns value');
}
done_testing;
```
## Test2::V0 现代框架
Test2::V0 是 Test::More 的现代替代品 —— 更丰富的断言、更好的诊断和可扩展性。
### 为什么选择 Test2?
* 使用哈希/数组构建器进行卓越的深层比较
* 失败时提供更好的诊断输出
* 具有更清晰作用域的子测试
* 可通过 Test2::Tools::\* 插件扩展
* 与 Test::More 测试向后兼容
### 使用构建器进行深层比较
```perl
use v5.36;
use Test2::V0;
# Hash builder — check partial structure
is(
$user->to_hash,
hash {
field name => 'Alice';
field email => match(qr/\@example\.com$/);
field age => validator(sub { $_ >= 18 });
# Ignore other fields
etc();
},
'user has expected fields'
);
# Array builder
is(
$result,
array {
item 'first';
item match(qr/^second/);
item DNE(); # Does Not Exist — verify no extra items
},
'result matches expected list'
);
# Bag — order-independent comparison
is(
$tags,
bag {
item 'perl';
item 'testing';
item 'tdd';
},
'has all required tags regardless of order'
);
```
### 子测试
```perl
use v5.36;
use Test2::V0;
subtest 'User creation' => sub {
my $user = User->new(name => 'Alice', email => 'alice@example.com');
ok($user, 'user object created');
is($user->name, 'Alice', 'name is set');
is($user->email, 'alice@example.com', 'email is set');
};
subtest 'User validation' => sub {
my $warnings = warns {
User->new(name => '', email => 'bad');
};
ok($warnings, 'warns on invalid data');
};
done_testing;
```
### 使用 Test2 进行异常测试
```perl
use v5.36;
use Test2::V0;
# Test that code dies
like(
dies { divide(10, 0) },
qr/Division by zero/,
'dies on division by zero'
);
# Test that code lives
ok(lives { divide(10, 2) }, 'division succeeds') or note($@);
# Combined pattern
subtest 'error handling' => sub {
ok(lives { parse_config('valid.json') }, 'valid config parses');
like(
dies { parse_config('missing.json') },
qr/Cannot open/,
'missing file dies with message'
);
};
done_testing;
```
## 测试组织与 prove
### 目录结构
```text
t/
├── 00-load.t # 验证模块编译
├── 01-basic.t # 核心功能
├── unit/
│ ├── config.t # 按模块划分的单元测试
│ ├── user.t
│ └── util.t
├── integration/
│ ├── database.t
│ └── api.t
├── lib/
│ └── TestHelper.pm # 共享测试工具
└── fixtures/
├── config.json # 测试数据文件
└── users.csv
```
### prove 命令
```bash
# Run all tests
prove -l t/
# Verbose output
prove -lv t/
# Run specific test
prove -lv t/unit/user.t
# Recursive search
prove -lr t/
# Parallel execution (8 jobs)
prove -lr -j8 t/
# Run only failing tests from last run
prove -l --state=failed t/
# Colored output with timer
prove -l --color --timer t/
# TAP output for CI
prove -l --formatter TAP::Formatter::JUnit t/ > results.xml
```
### .proverc 配置
```text
-l
--color
--timer
-r
-j4
--state=save
```
## 夹具与设置/拆卸
### 子测试隔离
```perl
use v5.36;
use Test2::V0;
use File::Temp qw(tempdir);
use Path::Tiny;
subtest 'file processing' => sub {
# Setup
my $dir = tempdir(CLEANUP => 1);
my $file = path($dir, 'input.txt');
$file->spew_utf8("line1\nline2\nline3\n");
# Test
my $result = process_file("$file");
is($result->{line_count}, 3, 'counts lines');
# Teardown happens automatically (CLEANUP => 1)
};
```
### 共享测试助手
将可重用的助手放在 `t/lib/TestHelper.pm` 中,并通过 `use lib 't/lib'` 加载。通过 `Exporter` 导出工厂函数,例如 `create_test_db()`、`create_temp_dir()` 和 `fixture_path()`。
## 模拟
### Test::MockModule
```perl
use v5.36;
use Test2::V0;
use Test::MockModule;
subtest 'mock external API' => sub {
my $mock = Test::MockModule->new('MyApp::API');
# Good: Mock returns controlled data
$mock->mock(fetch_user => sub ($self, $id) {
return { id => $id, name => 'Mock User', email => 'mock@test.com' };
});
my $api = MyApp::API->new;
my $user = $api->fetch_user(42);
is($user->{name}, 'Mock User', 'returns mocked user');
# Verify call count
my $call_count = 0;
$mock->mock(fetch_user => sub { $call_count++; return {} });
$api->fetch_user(1);
$api->fetch_user(2);
is($call_count, 2, 'fetch_user called twice');
# Mock is automatically restored when $mock goes out of scope
};
# Bad: Monkey-patching without restoration
# *MyApp::API::fetch_user = sub { ... }; # NEVER — leaks across tests
```
对于轻量级的模拟对象,使用 `Test::MockObject` 创建可注入的测试替身,使用 `->mock()` 并验证调用 `->called_ok()`。
## 使用 Devel::Cover 进行覆盖率分析
### 运行覆盖率分析
```bash
# Basic coverage report
cover -test
# Or step by step
perl -MDevel::Cover -Ilib t/unit/user.t
cover
# HTML report
cover -report html
open cover_db/coverage.html
# Specific thresholds
cover -test -report text | grep 'Total'
# CI-friendly: fail under threshold
cover -test && cover -report text -select '^lib/' \
| perl -ne 'if (/Total.*?(\d+\.\d+)/) { exit 1 if $1 < 80 }'
```
### 集成测试
对数据库测试使用内存中的 SQLite,对 API 测试模拟 HTTP::Tiny。
```perl
use v5.36;
use Test2::V0;
use DBI;
subtest 'database integration' => sub {
my $dbh = DBI->connect('dbi:SQLite:dbname=:memory:', '', '', {
RaiseError => 1,
});
$dbh->do('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)');
$dbh->prepare('INSERT INTO users (name) VALUES (?)')->execute('Alice');
my $row = $dbh->selectrow_hashref('SELECT * FROM users WHERE name = ?', undef, 'Alice');
is($row->{name}, 'Alice', 'inserted and retrieved user');
};
done_testing;
```
## 最佳实践
### 应做事项
* **遵循 TDD**:在实现之前编写测试(红-绿-重构)
* **使用 Test2::V0**:现代断言,更好的诊断
* **使用子测试**:分组相关断言,隔离状态
* **模拟外部依赖**:网络、数据库、文件系统
* **使用 `prove -l`**:始终将 lib/ 包含在 `@INC` 中
* **清晰命名测试**:`'user login with invalid password fails'`
* **测试边界情况**:空字符串、undef、零、边界值
* **目标 80%+ 覆盖率**:专注于业务逻辑路径
* **保持测试快速**:模拟 I/O,使用内存数据库
### 禁止事项
* **不要测试实现**:测试行为和输出,而非内部细节
* **不要在子测试之间共享状态**:每个子测试都应是独立的
* **不要跳过 `done_testing`**:确保所有计划的测试都已运行
* **不要过度模拟**:仅模拟边界,而非被测试的代码
* **不要在新项目中使用 `Test::More`**:首选 Test2::V0
* **不要忽略测试失败**:所有测试必须在合并前通过
* **不要测试 CPAN 模块**:相信库能正常工作
* **不要编写脆弱的测试**:避免过度具体的字符串匹配
## 快速参考
| 任务 | 命令 / 模式 |
|---|---|
| 运行所有测试 | `prove -lr t/` |
| 详细运行单个测试 | `prove -lv t/unit/user.t` |
| 并行测试运行 | `prove -lr -j8 t/` |
| 覆盖率报告 | `cover -test && cover -report html` |
| 测试相等性 | `is($got, $expected, 'label')` |
| 深层比较 | `is($got, hash { field k => 'v'; etc() }, 'label')` |
| 测试异常 | `like(dies { ... }, qr/msg/, 'label')` |
| 测试无异常 | `ok(lives { ... }, 'label')` |
| 模拟一个方法 | `Test::MockModule->new('Pkg')->mock(m => sub { ... })` |
| 跳过测试 | `SKIP: { skip 'reason', $count unless $cond; ... }` |
| TODO 测试 | `TODO: { local $TODO = 'reason'; ... }` |
## 常见陷阱
### 忘记 `done_testing`
```perl
# Bad: Test file runs but doesn't verify all tests executed
use Test2::V0;
is(1, 1, 'works');
# Missing done_testing — silent bugs if test code is skipped
# Good: Always end with done_testing
use Test2::V0;
is(1, 1, 'works');
done_testing;
```
### 缺少 `-l` 标志
```bash
# Bad: Modules in lib/ not found
prove t/unit/user.t
# Can't locate MyApp/User.pm in @INC
# Good: Include lib/ in @INC
prove -l t/unit/user.t
```
### 过度模拟
模拟*依赖项*,而非被测试的代码。如果你的测试只验证模拟返回了你告诉它的内容,那么它什么也没测试。
### 测试污染
在子测试内部使用 `my` 变量 —— 永远不要用 `our` —— 以防止状态在测试之间泄漏。
**记住**:测试是你的安全网。保持它们快速、专注和独立。新项目使用 Test2::V0,运行使用 prove,问责使用 Devel::Cover。Related Skills
swift-protocol-di-testing
基于协议的依赖注入,用于可测试的Swift代码——使用聚焦协议和Swift Testing模拟文件系统、网络和外部API。
perl-patterns
现代 Perl 5.36+ 的惯用法、最佳实践和约定,用于构建稳健、可维护的 Perl 应用程序。
rust-testing
Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage. Follows TDD methodology.
kotlin-testing
Kotest, MockK, coroutine testi, property-based testing ve Kover coverage ile Kotlin test kalıpları. İdiomatic Kotlin uygulamalarıyla TDD metodolojisini takip eder.
cpp-testing
C++ テストの作成/更新/修正、GoogleTest/CTest の設定、失敗またはフレーキーなテストの診断、カバレッジ/サニタイザーの追加時にのみ使用します。
python-testing
Python testing best practices using pytest including fixtures, parametrization, mocking, coverage analysis, async testing, and test organization. Use when writing or improving Python tests.
golang-testing
Go testing best practices including table-driven tests, test helpers, benchmarking, race detection, coverage analysis, and integration testing patterns. Use when writing or improving Go tests.
workspace-surface-audit
Audit the active repo, MCP servers, plugins, connectors, env surfaces, and harness setup, then recommend the highest-value ECC-native skills, hooks, agents, and operator workflows. Use when the user wants help setting up Claude Code or understanding what capabilities are actually available in their environment.
safety-guard
Use this skill to prevent destructive operations when working on production systems or running agents autonomously.
repo-scan
Cross-stack source code asset audit — classifies every file, detects embedded third-party libraries, and delivers actionable four-level verdicts per module with interactive HTML reports.
project-flow-ops
Operate execution flow across GitHub and Linear by triaging issues and pull requests, linking active work, and keeping GitHub public-facing while Linear remains the internal execution layer. Use when the user wants backlog control, PR triage, or GitHub-to-Linear coordination.
manim-video
Build reusable Manim explainers for technical concepts, graphs, system diagrams, and product walkthroughs, then hand off to the wider ECC video stack if needed. Use when the user wants a clean animated explainer rather than a generic talking-head script.