关于 php-testing
php-testing 是面向 PHP 开发者的测试学习技能,内容涵盖从基础测试到 CI/CD,并按主题和水平组织 PHPUnit、Pest 与 Mockery 指南及示例。
主要功能
- 01PHPUnit 11 基础
- 02Pest 3 测试模式
- 03使用 Mockery 和 Prophecy 模拟
- 04TDD 与集成测试
- 05CI/CD 指南与示例
适用场景
- 01学习 PHPUnit 测试结构与断言
- 02选择模拟对象、桩或间谍
- 03测试数据库和 API 集成
- 04排查 CI 中失败的测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ pluginagentmarketplace/ custom-plugin-php --skill php-testing安装后在 Claude Code 中输入/php-testing确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/config.yamlschema.jsonreferences/GUIDE.mdPATTERNS.mdscripts/validate.py详细介绍
PHP 测试技能
掌握 PHP 测试策略的原子技能
概述
全面的 PHP 测试技能,涵盖 PHPUnit 11、Pest 3、TDD 方法论、模拟策略和 CI/CD 集成。
技能参数
输入验证
interface SkillParams {
topic:
| "phpunit" // PHPUnit framework
| "pest" // Pest framework
| "mocking" // Mockery, Prophecy
| "tdd" // Test-driven development
| "integration" // Database, API testing
| "ci-cd"; // GitHub Actions, GitLab CI
level: "beginner" | "intermediate" | "advanced";
framework?: "laravel" | "symfony" | "none";
coverage_goal?: number;
}
验证规则
validation:
topic:
required: true
allowed: [phpunit, pest, mocking, tdd, integration, ci-cd]
level:
required: true
framework:
default: "none"
学习模块
模块 1:PHPUnit 基础知识
beginner:
- Test case structure
- Basic assertions
- Running tests
intermediate:
- Data providers
- Fixtures (setUp/tearDown)
- Test doubles
advanced:
- Attributes (#[Test], #[DataProvider])
- Code coverage
- Parallel execution
模块 2:Pest 框架
beginner:
- Expectations syntax
- Test organization
- Groups and filtering
intermediate:
- Higher-order tests
- Datasets
- Hooks
advanced:
- Mutation testing (--mutate)
- Architecture testing
- Custom expectations
模块 3:模拟策略
beginner:
- Mock basics
- Stubs vs mocks
- Simple expectations
intermediate:
- Partial mocks
- Spies
- Argument matching
advanced:
- Mock chains
- Return callbacks
- Exception testing
错误处理与重试逻辑
errors:
TEST_FAILURE:
code: "TEST_001"
recovery: "Compare expected vs actual, check setup"
MOCK_ERROR:
code: "TEST_002"
recovery: "Verify mock expectations and injection"
FLAKY_TEST:
code: "TEST_003"
recovery: "Check isolation, fix race conditions"
retry:
max_attempts: 2
backoff:
type: linear
delay_ms: 100
代码示例
PHPUnit 测试(PHP 8.2+)
<?php
declare(strict_types=1);
namespace Tests\Unit;
use App\Services\Calculator;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\DataProvider;
final class CalculatorTest extends TestCase
{
private Calculator $calculator;
protected function setUp(): void
{
$this->calculator = new Calculator();
}
#[Test]
public function it_adds_two_numbers(): void
{
$result = $this->calculator->add(2, 3);
$this->assertSame(5, $result);
}
#[Test]
#[DataProvider('divisionProvider')]
public function it_divides_correctly(int $a, int $b, float $expected): void
{
$result = $this->calculator->divide($a, $b);
$this->assertEqualsWithDelta($expected, $result, 0.0001);
}
public static function divisionProvider(): array
{
return [
'whole' => [10, 2, 5.0],
'decimal' => [7, 2, 3.5],
];
}
#[Test]
public function it_throws_on_division_by_zero(): void
{
$this->expectException(\DivisionByZeroError::class);
$this->calculator->divide(10, 0);
}
}
Pest 测试
<?php
use App\Models\User;
use function Pest\Laravel\{actingAs, post, assertDatabaseHas};
describe('User Registration', function () {
it('allows new user registration', function () {
post('/register', [
'name' => 'John',
'email' => '[email protected]',
'password' => 'password',
'password_confirmation' => 'password',
])
->assertRedirect('/dashboard');
assertDatabaseHas('users', ['email' => '[email protected]']);
});
it('requires valid email', function () {
post('/register', ['email' => 'invalid'])
->assertSessionHasErrors('email');
});
})->group('auth');
使用 Mockery 进行模拟
<?php
declare(strict_types=1);
namespace Tests\Unit;
use App\Services\UserService;
use App\Repositories\UserRepository;
use Mockery;
use PHPUnit\Framework\TestCase;
final class UserServiceTest extends TestCase
{
public function test_creates_user(): void
{
// Arrange
$repository = Mockery::mock(UserRepository::class);
$repository
->shouldReceive('create')
->once()
->with(['name' => 'John', 'email' => '[email protected]'])
->andReturn(new User(['id' => 1]));
$service = new UserService($repository);
// Act
$user = $service->createUser([
'name' => 'John',
'email' => '[email protected]',
]);
// Assert
$this->assertEquals(1, $user->id);
}
protected function tearDown(): void
{
Mockery::close();
}
}
CI/CD 配置(GitHub Actions)
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
coverage: xdebug
- name: Install dependencies
run: composer install --no-progress
- name: Run tests
run: vendor/bin/phpunit --coverage-clover coverage.xml
- name: Upload coverage
uses: codecov/codecov-action@v3
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 测试在本地通过,在 CI 中失败 | 环境差异 | 检查 PHP 版本、数据库状态 |
| 未调用模拟对象 | 未注入 | 验证 DI,不要在类内部实例化 |
| 数据库污染 | 状态共享 | 使用 RefreshDatabase trait |
| 测试缓慢 | 数据库操作过多 | 使用模拟对象,并行运行 |
质量指标
| 指标 | 目标 |
|---|---|
| 代码覆盖率 | ≥80% |
| 测试速度 | 完整测试套件 <5 分钟 |
| 不稳定率 | 0% |
| 测试隔离度 | 100% |
用法
Skill("php-testing", {topic: "mocking", level: "intermediate"})
评论
支持 Markdown