Mockery/PhpUnit:测试成功但错误

Posted

技术标签:

【中文标题】Mockery/PhpUnit:测试成功但错误【英文标题】:Mockery/PhpUnit: test is successful but it is wrong 【发布时间】:2019-06-18 04:19:43 【问题描述】:

我有一个读取外部 API 的 Domoticz 类。

class Domoticz extends HeaterService implements DomoticControllerInterface 

public function getFromApiCurrentHeaterStatus($current_heater)
    
        $current_heater = json_decode($current_heater);

        if (!isset($current_heater->result)) 
            throw new \Exception('There is a problem retrieving heater status');
        

        $heater = array();

        foreach ($current_heater->result as $result) 

            $heater['idx'] = (int)$result->idx;
            $heater['status'] = $result->Status;

        

        return $heater;
    

方法getFromApiCurrentHeaterStatus返回一个数组。

这是我的测试

    class DomoticzTest extends TestCase


/**
 * This is a copy of real json got from an API call
 */
private $heater_answer = '"result":"2":"Status":"Off","idx":"17"';

/**
 * Test that from an answer as $heater_answer, we can get an array with idx and status
 *
 */
public function testThatWeCanGetAnArrayFromHeaterAnswer()

    $right_heater_array = array('idx' => 17, 'status' => 'Off');
    $right_array_we_want = $right_heater_array; // we need to get an array
    $wrong_heater_array = array('idx' => 11, 'status' => 'On');
    $wrong_array_we_dont_want = $wrong_heater_array;

    $mock = $this->getMockBuilder('\App\Libs\Domoticz')
        ->disableOriginalConstructor()
        ->getMock();

    $mock
        ->expects($this->once())
        ->method('getFromApiCurrentHeaterStatus')
        ->with($this->heater_answer)
        ->willReturn($right_array_we_want);

    $heater = $mock->getFromApiCurrentHeaterStatus($this->heater_answer);
    $this->assertEquals($right_array_we_want,$heater);

测试通过。实际上,通过“真正的”API 调用 ($this->heater_answer),我们得到了一个数组

$heater['idx'] = 17;
$heater['status'] = 'Off';

现在,我确实尝试更改属性 heater_answer,例如将 idx 从 17 更改为 2,或者状态,在每种情况下测试都通过了。

换句话说:真正的方法是不是没有执行?如何强制测试执行真正的方法?

【问题讨论】:

【参考方案1】:

你为什么嘲笑它?您没有在该方法中进行实际的 API 调用..

由于您正在测试您的方法是否将实际 heater 答案解码为正确格式,因此您的测试应如下所示:

private $heater_answer = '"result":"2":"Status":"Off","idx":"17"';

public function testThatWeCanGetAnArrayFromHeaterAnswer()

    $mock = $this->getMockBuilder('\App\Libs\Domoticz')
        ->setMethodsExcept(['getFromApiCurrentHeaterStatus'])
        ->disableOriginalConstructor()
        ->getMock();

    $response = $mock->getFromApiCurrentHeaterStatus($this->heater_answer); 

    $this->assertEquals([
        'idx' => 17, 
        'status' => 'Off'
    ], $response);

通过添加setMethodsExcept(),该数组中定义的方法将不会被测试替身替换。然后你就可以实际测试它了。

【讨论】:

我在嘲笑,因为 __construct()(例如)初始化 API 调用(用户/密码/令牌)等,所以我不能拥有原始构造函数。

以上是关于Mockery/PhpUnit:测试成功但错误的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Mockery 集成测试

嘲笑php测试中的碳对象

PH测试工具对比

未捕获的错误:找不到类“PHP_Token_ELLIPSIS”

未找到但正确包含 PHPUnit 类

如何使用 httpbackend 测试 Restangular http 调用以测试成功和错误情况?