本文目录导读:

我来详细说明PHP项目中PHPUnit的配置、使用和运行方法。
安装PHPUnit
使用Composer安装(推荐)
# 全局安装 composer global require phpunit/phpunit # 或作为项目依赖 composer require --dev phpunit/phpunit
版本选择建议
{
"require-dev": {
"phpunit/phpunit": "^9.6" // PHP 7.3+
}
}
基本目录结构
project/
├── src/
│ ├── Calculator.php
│ └── UserService.php
├── tests/
│ ├── Unit/
│ │ └── CalculatorTest.php
│ └── Feature/
│ └── UserServiceTest.php
├── phpunit.xml
├── composer.json
└── vendor/
PHPUnit配置文件 (phpunit.xml)
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
verbose="true"
stopOnFailure="false">
<php>
<ini name="error_reporting" value="-1"/>
<env name="APP_ENV" value="testing"/>
<env name="DB_HOST" value="localhost"/>
</php>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory>src</directory>
</include>
<exclude>
<directory>src/Exceptions</directory>
</exclude>
</coverage>
<logging>
<junit outputFile="build/report.xml"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
编写测试类
基础测试示例
<?php
// tests/Unit/CalculatorTest.php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use App\Calculator;
class CalculatorTest extends TestCase
{
private Calculator $calculator;
protected function setUp(): void
{
parent::setUp();
$this->calculator = new Calculator();
}
public function testAddition(): void
{
$result = $this->calculator->add(2, 3);
$this->assertEquals(5, $result);
$this->assertIsInt($result);
}
public function testDivision(): void
{
$result = $this->calculator->divide(10, 2);
$this->assertEquals(5, $result);
}
public function testDivisionByZero(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot divide by zero');
$this->calculator->divide(10, 0);
}
/**
* @dataProvider additionProvider
*/
public function testAddWithDataProvider(int $a, int $b, int $expected): void
{
$result = $this->calculator->add($a, $b);
$this->assertEquals($expected, $result);
}
public function additionProvider(): array
{
return [
[1, 2, 3],
[0, 0, 0],
[-1, -1, -2],
[100, 200, 300]
];
}
}
Mock对象示例
<?php
// tests/Feature/UserServiceTest.php
namespace Tests\Feature;
use PHPUnit\Framework\TestCase;
use App\UserService;
use App\Repositories\UserRepository;
use App\Mail\WelcomeMail;
use Mockery;
class UserServiceTest extends TestCase
{
private UserService $userService;
private $userRepositoryMock;
private $mailerMock;
protected function setUp(): void
{
parent::setUp();
// 创建Mock
$this->userRepositoryMock = $this->createMock(UserRepository::class);
$this->mailerMock = $this->createMock(\App\Mail\Mailer::class);
$this->userService = new UserService(
$this->userRepositoryMock,
$this->mailerMock
);
}
public function testCreateUser(): void
{
$userData = [
'name' => 'John Doe',
'email' => 'john@example.com'
];
$expectedUser = (object) array_merge($userData, ['id' => 1]);
// 设置Mock期望
$this->userRepositoryMock
->expects($this->once())
->method('create')
->with($userData)
->willReturn($expectedUser);
$this->mailerMock
->expects($this->once())
->method('send')
->with($this->isInstanceOf(WelcomeMail::class));
$result = $this->userService->createUser($userData);
$this->assertEquals($expectedUser, $result);
}
public function testGetUserByIdNotFound(): void
{
$this->userRepositoryMock
->expects($this->once())
->method('findById')
->with(999)
->willReturn(null);
$this->expectException(\RuntimeException::class);
$this->userService->getUserById(999);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
}
运行测试
命令行运行
# 运行所有测试 ./vendor/bin/phpunit # 运行特定测试套件 ./vendor/bin/phpunit --testsuite Unit # 运行特定测试文件 ./vendor/bin/phpunit tests/Unit/CalculatorTest.php # 运行特定测试方法 ./vendor/bin/phpunit --filter testAddition tests/Unit/CalculatorTest.php # 生成覆盖率报告 ./vendor/bin/phpunit --coverage-html coverage/
运行指定测试组
class CalculatorTest extends TestCase
{
/**
* @group slow
* @group database
*/
public function testComplexCalculation(): void
{
// ...
}
}
./vendor/bin/phpunit --group slow
常用断言方法
$this->assertEquals($expected, $actual);
$this->assertSame($expected, $actual); // 严格比较
$this->assertTrue($condition);
$this->assertFalse($condition);
$this->assertNull($value);
$this->assertNotNull($value);
$this->assertInstanceOf($class, $object);
$this->assertArrayHasKey($key, $array);
$this->assertCount($expectedCount, $array);
$this->assertStringContainsString($needle, $haystack);
$this->assertMatchesRegularExpression('/pattern/', $string);
高级配置
数据库测试配置
<php>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
</php>
并行测试
# 使用paratest进行并行测试 composer require --dev brianium/paratest ./vendor/bin/paratest -p4 tests/
常见问题解决
内存不足
php -d memory_limit=-1 ./vendor/bin/phpunit
跳过慢速测试
class CalculatorTest extends TestCase
{
/**
* @requires extension pdo
*/
public function testWithDatabase(): void
{
// ...
}
}
composer.json配置建议
{
"scripts": {
"test": "phpunit",
"test-coverage": "phpunit --coverage-html coverage",
"test-unit": "phpunit --testsuite Unit",
"test-feature": "phpunit --testsuite Feature"
}
}
最佳实践
- 测试命名规范:测试方法名使用
test前缀或@test注解 - 单一断言:每个测试方法只测试一个功能点
- 使用Fixtures:
setUp()和tearDown()方法管理测试资源 - 避免外部依赖:使用Mock对象隔离测试
- 保持测试独立:测试之间不应相互依赖
这样配置后,你就可以通过简单的命令运行PHPUnit测试了,记得定期运行测试确保代码质量。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播