我最近开始使用PHPUnit进行单元测试,并且我构建了测试以检查函数成功和失败时的正确行为。
例如,我可以测试函数connectToDevice()
,期望连接成功时返回true
,否则返回false
。然后我会:
public function testConnectToDeviceSuccess()
{
$this->assertTrue($this->myObject->connectToDevice());
}
public function testConnectToDeviceFailure()
{
$this->assertFalse($this->myObject->connectToDevice());
}
目前其中一个函数必然会失败,那么PHPUnit会报告我1失败。相反,只有当两个函数都失败时,我才会将其设置为标记测试失败。因此,当1成功时,将跳过另一个。
这是否可以在PHPUnit中将这些测试保存在两个不同的函数中?
答案 0 :(得分:1)
我认为您遇到的问题是您缺少确保正确测试结果的设置。这可能听起来有点奇怪,但请考虑这种情况
class ConnectedResource
{
private $connector;
public function __construct($connector)
{
$this->connector = $connector;
}
public function connectToDevice()
{
try {
$this->connector->connect();
} catch (\Exception $e) {
return false;
}
return true;
}
}
这真的很简单,但关键是要测试两个路径:connect()成功和异常。
你现在要做的测试是
public function testSuccessfulConnectReturnsTrue()
{
$connector = new Connector(
// config to make a successful connection
);
$myObject = new ConnectedResource($connector);
$this->assertTrue($myObject->connectToDevice());
}
public function testFailedConnectReturnsFalse()
{
$connector = new Connector(
// invalid config that will raise an exception
);
$myObject = new ConnectedResource($connector);
$this->assertFalse($myObject->connectToDevice());
}
现在两个测试都有效,因为它们使用不同的连接(一个有效,一个无效)。
另一种可能性是传入模拟连接器。换句话说,您可以创建一个虚拟对象,而不是真正的连接器,您可以自己决定$this->connector->connect()
将返回什么。把它想象成"假设我有一个返回true的连接器然后ConnectedResource应该像这样"。这个代码看起来像这样:
public function testSuccessfulConnectReturnsTrue()
{
$connector = $this->createMock(Connector::class);
$connector->expect($this->any())
->method('connect')
->willReturn(true)
;
$myObject = new ConnectedResource($connector);
$this->assertTrue($myObject->connectToDevice());
}
对于失败场景,它看起来像这样:
public function testFailedConnectReturnsFalse()
{
$connector = $this->createMock(Connector::class);
$connector->expect($this->any())
->method('connect')
->willReturn($this->throwException(new Exception))
;
$myObject = new ConnectedResource($connector);
$this->assertTrue($myObject->connectToDevice());
}
现在,您可以控制测试范围之外的所有内容(连接),并仅测试connectToDevice()
中定义的行为。这将使您的测试对另一个类中的更改安全,但可能会导致问题,例如在将来的更新中connect()函数更改,例如参数被添加或更改。
重要的是,您必须确保满足运行测试的要求。
答案 1 :(得分:1)
有可能(您可以根据另一项测试的结果进行一项测试,请参阅Test Dependencies),但请考虑您在此处的问题中有效测试的内容,将其包含在一个测试中:
public function testConnectToDeviceBehavior()
{
$actual = $this->myObject->connectToDevice() === $this->myObject->connectToDevice();
$this->assertTrue($actual);
}
如果且仅当连接到设备时没有两次给出相同的结果,这将使测试失败。
你可以用多个测试的测试依赖关系来编写它,但是这很可能不是你最想测试的。
但是,如果,请查看Phpunit文档的链接部分。
否则考虑the other answer中概述的内容,使用依赖注入并使用工作和连接失败来测试对象。</ p>