phpunit基础使用指南
目录
PHPUnit 单测基本使用
在 PHP 单元测试中,Mock 是一种非常重要的工具,可以模拟对象的行为,帮助我们隔离依赖,专注于测试代码的逻辑。以下是关于 Mock 的多种创建方式、相关set
方法的使用,以及常用设置模拟属性或方法的方式,附带相应的范例。
1. Mock 的创建方式
1.1 使用createMock
方法
createMock
是最简单的方式,用于创建一个完整的 Mock 对象。注:PHPUnit 6.0 及以上版本才支持这个方法。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->createMock(MyClass::class);
$mock->method('myMethod')->willReturn('mocked value');
$this->assertEquals('mocked value', $mock->myMethod());
}
}
1.2 使用getMockBuilder
方法
getMockBuilder
提供了更灵活的配置选项,例如禁用构造函数、指定构造参数等。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->getMockBuilder(MyClass::class)
->disableOriginalConstructor()
->setMethods(['myMethod'])
->getMock();
$mock->expects($this->any())
->method('myMethod')
->willReturn('mocked value');
$this->assertEquals('mocked value', $mock->myMethod());
}
}
1.3 使用getMockForAbstractClass
方法
如果需要为抽象类创建 Mock 对象,可以使用getMockForAbstractClass
。
use PHPUnit\Framework\TestCase;
abstract class AbstractClass
{
public abstract function myMethod();
}
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->getMockForAbstractClass(AbstractClass::class);
$mock->expects($this->any())
->method('myMethod')
->willReturn('mocked value');
$this->assertEquals('mocked value', $mock->myMethod());
}
}
2. Mock 的set
方法及相关配置
2.1 设置方法的预期调用次数
可以使用expects
方法来指定 Mock 方法的调用次数。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->createMock(MyClass::class);
$mock->expects($this->once()) // 只调用一次
->method('myMethod')
->willReturn('mocked value');
$mock->myMethod();
// 调用第二次会抛出异常,因为只允许调用一次
}
}
2.2 设置方法的返回值
使用willReturn
方法可以指定 Mock 方法的返回值。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->createMock(MyClass::class);
$mock->method('myMethod')->willReturn('mocked value');
$this->assertEquals('mocked value', $mock->myMethod());
}
}
2.3 设置方法的参数匹配
可以使用with
方法来指定 Mock 方法的参数。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->createMock(MyClass::class);
$mock->expects($this->once())
->method('myMethod')
->with('expected param') // 指定参数
->willReturn('mocked value');
$mock->myMethod('expected param');
$this->assertEquals('mocked value', $mock->myMethod('expected param'));
}
}
3. 常用设置模拟属性或方法的方式
3.1 模拟方法的返回值
通过willReturn
方法可以模拟方法的返回值。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->createMock(MyClass::class);
$mock->method('myMethod')->willReturn('mocked value');
$this->assertEquals('mocked value', $mock->myMethod());
}
}
3.2 模拟方法抛出异常
可以使用willThrowException
方法来模拟方法抛出异常。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->createMock(MyClass::class);
$mock->expects($this->once())
->method('myMethod')
->willThrowException(new \Exception('Mocked Exception'));
$this->expectException(\Exception::class);
$mock->myMethod();
}
}
注:PHPUnit 6.0 及以上版本:推荐使用 expectException 方法。PHPUnit 5.x 及更早版本:使用@expectedException 注解。
3.3 模拟方法返回调用参数
使用returnArgument
方法可以让 Mock 方法返回调用时的参数。
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testMyMethod()
{
$mock = $this->createMock(MyClass::class);
$mock->method('myMethod')->willReturnArgument(0);
$this->assertEquals('param', $mock->myMethod('param'));
}
}
Mock 对象的所有方法及返回 null
在 PHPUnit 中,如果你想让 Mock 对象的所有方法都可以被调用,并且默认返回null
(或者任何指定的默认值),同时不需要保存这些方法的调用状态,可以通过setMethods
和willReturn
方法来实现。
通过setMethods(null)
和willReturn(null)
,你可以让 Mock 对象的所有方法都可以被调用,并且默认返回null
。这种方式非常适合在测试中快速模拟对象行为,而不需要关心具体的实现细节。
以下是一个具体的实现方式:
使用setMethods(null)
和willReturn(null)
通过setMethods(null)
,你可以让 Mock 对象的所有方法都可以被调用,并且通过willReturn(null)
设置默认返回值为null
。
示例代码:
use PHPUnit\Framework\TestCase;
class MyClass
{
public function methodA()
{
return "Original methodA";
}
public function methodB($param)
{
return "Original methodB with param: $param";
}
public function methodC()
{
return "Original methodC";
}
}
class MyTest extends TestCase
{
public function testMockAllMethods()
{
// 创建 Mock 对象,允许所有方法被调用
$mock = $this->getMockBuilder(MyClass::class)
->setMethods(null) // 允许所有方法被调用
->getMock();
// 设置所有方法的默认返回值为 null
$mock->method($this->anything())->willReturn(null);
// 测试方法调用
$this->assertNull($mock->methodA());
$this->assertNull($mock->methodB("test"));
$this->assertNull($mock->methodC());
}
}
关键点说明
-
setMethods(null)
:- 默认情况下,Mock 对象不会调用原始类的方法。通过
setMethods(null)
,你可以允许 Mock 对象的所有方法被调用。 - 如果不设置
setMethods(null)
,Mock 对象只会调用你在setMethods
中明确指定的方法,其他方法会抛出异常。
- 默认情况下,Mock 对象不会调用原始类的方法。通过
-
willReturn(null)
:- 使用
willReturn(null)
可以设置 Mock 方法的默认返回值为null
。 - 如果你希望返回其他默认值,比如
false
或0
,可以将willReturn(null)
替换为willReturn(false)
或willReturn(0)
。
- 使用
-
method($this->anything())
:- 这里使用
$this->anything()
来匹配任意方法名,确保所有方法调用都会返回指定的默认值。
- 这里使用
注意事项
- 如果你的类中有构造函数,并且构造函数中有一些初始化逻辑,可能需要使用
disableOriginalConstructor()
来禁用构造函数,以避免不必要的副作用。 - 如果你的类中有
__toString()
方法,或者某些方法需要返回特定类型(比如字符串或数组),你可能需要为这些方法单独设置返回值。
禁用构造函数示例:
如果类MyClass
有一个构造函数,你可以这样设置:
$mock = $this->getMockBuilder(MyClass::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
$mock->method($this->anything())->willReturn(null);
Mock 静态类与静态方法
在 Mockery 中,模拟静态类和静态方法的方式与模拟普通对象和方法有所不同。Mockery 通过mock
方法和shouldReceive
方法来实现对静态类和静态方法的模拟。以下是具体的实现方式和示例:
模拟静态类和静态方法
1. 使用mock
方法模拟静态类
Mockery 允许通过mock
方法创建一个静态类的模拟对象,并通过shouldReceive
方法定义静态方法的行为。
示例代码:
use Mockery as m;
class StaticClass
{
public static function staticMethod()
{
return "Original value";
}
}
class MyTest extends \PHPUnit\Framework\TestCase
{
public function testStaticMethod()
{
// 创建静态类的模拟对象
$mock = m::mock('alias:StaticClass');
// 定义静态方法的行为
$mock->shouldReceive('staticMethod')
->andReturn('Mocked value');
// 调用静态方法并验证返回值
$this->assertEquals('Mocked value', StaticClass::staticMethod());
}
public function tearDown(): void
{
// 清理 Mockery 的模拟对象
m::close();
}
}
2. 使用shouldReceive
方法模拟静态方法
shouldReceive
方法用于定义模拟对象的行为,包括返回值、抛出异常等。
示例代码:
use Mockery as m;
class StaticClass
{
public static function staticMethod($param)
{
return "Original value with param: $param";
}
}
class MyTest extends \PHPUnit\Framework\TestCase
{
public function testStaticMethodWithParam()
{
// 创建静态类的模拟对象
$mock = m::mock('alias:StaticClass');
// 定义静态方法的行为
$mock->shouldReceive('staticMethod')
->with('testParam') // 指定参数
->andReturn('Mocked value with param');
// 调用静态方法并验证返回值
$this->assertEquals('Mocked value with param', StaticClass::staticMethod('testParam'));
}
public function tearDown(): void
{
// 清理 Mockery 的模拟对象
m::close();
}
}
3. 模拟静态方法抛出异常
Mockery 可以通过shouldReceive
方法定义静态方法抛出异常。
示例代码:
use Mockery as m;
class StaticClass
{
public static function staticMethod()
{
return "Original value";
}
}
class MyTest extends \PHPUnit\Framework\TestCase
{
public function testStaticMethodThrowsException()
{
// 创建静态类的模拟对象
$mock = m::mock('alias:StaticClass');
// 定义静态方法抛出异常
$mock->shouldReceive('staticMethod')
->andThrow(new \Exception('Mocked Exception'));
// 验证异常
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Mocked Exception');
// 调用静态方法,触发异常
StaticClass::staticMethod();
}
public function tearDown(): void
{
// 清理 Mockery 的模拟对象
m::close();
}
}
注:PHPUnit 6.0 及以上版本:推荐使用 expectException 方法。PHPUnit 5.x 及更早版本:使用@expectedException 注解。
注意事项
- 使用
alias
:在模拟静态类时,需要使用alias
关键字,例如m::mock('alias:StaticClass')
。 - 清理模拟对象:在测试完成后,需要调用
m::close()
来清理 Mockery 的模拟对象。 - 参数匹配:可以通过
with
方法指定静态方法的参数。
通过以上方式,Mockery 可以灵活地模拟静态类和静态方法的行为,满足单元测试中的各种需求。
phpunit 断言异常不同版本
在 PHPUnit 的旧版本中(如 PHPUnit 3.x 和 4.x),setExpectedException
和 getExpectedException
是用于断言异常的方法。这些方法在 PHPUnit 5.x 中被引入的 @expectedException
注解所取代,并在 PHPUnit 6.x 中被 expectException
方法完全替代。
- PHPUnit 3.x 和 4.x:使用
setExpectedException
和getExpectedException
方法。 - PHPUnit 5.x:使用
@expectedException
注解。 - PHPUnit 6.x 及更高版本:使用
expectException
方法。
setExpectedException 方法
setExpectedException
方法用于设置测试中期望抛出的异常类型。如果测试代码中没有抛出指定的异常,测试将失败。
使用方式:
public function testException()
{
$this->setExpectedException('InvalidArgumentException'); // 设置期望的异常类型
throw new InvalidArgumentException("Test exception");
}
getExpectedException 方法
getExpectedException
方法用于获取当前设置的期望异常类型。它通常用于调试或验证异常设置是否正确。
使用方式:
public function testException()
{
$this->setExpectedException('InvalidArgumentException');
$expectedException = $this->getExpectedException(); // 获取期望的异常类型
$this->assertEquals('InvalidArgumentException', $expectedException);
throw new InvalidArgumentException("Test exception");
}
替代方法
从 PHPUnit 5.x 开始,推荐使用 @expectedException
注解来替代 setExpectedException
方法。例如:
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
throw new InvalidArgumentException("Test exception");
}
从 PHPUnit 6.x 开始,进一步引入了 expectException
方法,提供了更灵活的异常断言:
public function testException()
{
$this->expectException(InvalidArgumentException::class);
throw new InvalidArgumentException("Test exception");
}
PHPBench 基准测试
PHPUnit 本身不提供基准测试功能,但可以通过 PHPBench 等工具来实现性能测试和基准比较。PHPBench 是一个强大的基准测试框架,支持多种功能和报告格式,适合与 PHPUnit 结合使用。
PHPUnit 本身并不直接提供基准测试(Benchmark)功能,但可以通过其他工具或扩展来实现性能测试和基准比较。以下是一些相关工具和方法:
1. PHPBench
PHPBench 是一个专门用于性能基准测试的工具,类似于 PHPUnit 用于单元测试。它提供了以下功能:
- 重复执行:多次运行代码以确定平均执行时间。
- 迭代采样:多次采样并提供聚合统计数据。
- 进程隔离:每次迭代在独立进程中执行,避免相互干扰。
- 报告生成:支持多种输出格式(如控制台、CSV、HTML)。
- 内存使用监控:监控测试代码的内存使用情况。
PHPBench 可以通过 Composer 安装:
composer require phpbench/phpbench --dev
2. PHPUnit 与 PHPBench 的集成
虽然 PHPUnit 本身不支持基准测试,但可以通过 PHPBench 来扩展其功能。例如,可以将 PHPUnit 测试类与 PHPBench 集成,通过注解或配置文件来定义基准测试。
3. 使用 PHPUnit 的--repeat
选项
PHPUnit 提供了--repeat
命令行选项,可以重复运行测试多次。虽然这不是一个完整的基准测试工具,但可以通过重复运行测试来观察性能变化:
phpunit --repeat 100 tests/MyTest.php
4. 其他基准测试工具
除了 PHPBench,还可以使用其他工具(如Benchmark
扩展)来测试代码的执行时间。例如,Benchmark
扩展提供了Timer
、Iterate
和Profiler
类,用于测量代码的执行时间和性能。
安装Benchmark
扩展:
pear install Benchmark
示例:使用 PHPBench 进行基准测试
以下是一个简单的 PHPBench 基准测试示例:
<?php
// 基准测试类
class MyBenchmark extends \PhpBench\Benchmark
{
public function benchAddition()
{
$result = 0;
for ($i = 0; $i < 100000; $i++) {
$result += $i;
}
}
}
运行基准测试:
vendor/bin/phpbench run --report=default
9ong@TsingChan 文章内容由 AI 辅助生成。