PHPUnit - 当两个相关函数失败时将测试标记为失败

时间:2017-06-29 09:34:12

标签: php unit-testing phpunit

我最近开始使用PHPUnit进行单元测试,并且我构建了测试以检查函数成功和失败时的正确行为。

例如,我可以测试函数connectToDevice(),期望连接成功时返回true,否则返回false。然后我会:

public function testConnectToDeviceSuccess()
{
    $this->assertTrue($this->myObject->connectToDevice());
}

public function testConnectToDeviceFailure()
{
    $this->assertFalse($this->myObject->connectToDevice());
}

目前其中一个函数必然会失败,那么PHPUnit会报告我1失败。相反,只有当两个函数都失败时,我才会将其设置为标记测试失败。因此,当1成功时,将跳过另一个。

这是否可以在PHPUnit中将这些测试保存在两个不同的函数中?

2 个答案:

答案 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>