phpunit - 不使用注入进行模拟?

问题描述 投票:0回答:1

我正在学习 phpunit 并注意到很多示例似乎是模拟一个类,然后将其注入另一个类,然后测试该方法。我想知道如果我想不注射就测试怎么办?

现在,我希望它失败,所以我知道它正在使用模拟返回值,但测试通过是因为它没有使用模拟值。我怎样才能使用模拟部分?谢谢。

这是一个简单的例子:

class Check
{
    public function checkAdd($num1, $num2)
    {
        $sum = $num1 + $num2;
        $calculator = new Calculator();
        $res = $calculator->add($num1, $num2);
        return ($sum == $res);
    }
}
class Calculator
{
    public function add($num1, $num2)
    {
        return $num1 + $num2;
    }
}

use PHPUnit\Framework\TestCase;

require_once __DIR__ . '/../Check.php';
require_once __DIR__ . '/../Calculator.php';

class CheckTest extends TestCase
{
    public function testValidateAdd()
    {
        $calculatorMock = $this->getMockBuilder(Calculator::class)->getMock();
        $calculatorMock->method('add')->willReturn(3);

        $check = new Check();
        $result = $check->checkAdd(5, 2);
        $this->assertTrue($result);
    }
}
mocking phpunit
1个回答
0
投票

由于

public function checkAdd($num1, $num2)
正在使用
Calculator

的具体实现
public function checkAdd($num1, $num2)
{
  $sum = $num1 + $num2;
  $calculator = new Calculator(); // !! HERE !!
  $res = $calculator->add($num1, $num2);

  return ($sum == $res);
}

您将无法用测试替身(模拟、存根等)替换它。

为了使用测试替身,您必须以某种方式将其处理为 SUS(被测系统)。在你的例子中类似:

  • Check
    创建构造函数并传递计算器
  • 将计算器传递给
    checkAdd
    函数(我不会这么做;尽管如此,我还是想分享)

现在您知道为什么不起作用以及如何解决它,让我们分析您的代码。 由于

Calculator
没有副作用(它是一个纯函数)并且不是外部依赖项(如数据库、文件系统、网络、api 等),因此并不严格需要使用测试替身来替换它。请记住,每次使用测试替身时,您都会在测试维护方面付出一些额外的努力(就好像您很可能更改实现一样,您也需要更改测试代码)。

硬币的另一面,通过您的实现,您正在创建一个对象并在同一代码片段中使用它。这意味着您正在

Check
Calculator
之间创建耦合。这本身并不是一个糟糕的设计选择,只是想强调一下。

顺便说一句,有人可能会说,使用具体的实现会违反单元测试的基本原则,因为人们往往对单元是什么以及孤立测试的含义感到困惑。用几句话来解释一下:单元只是您正在测试的代码,因此可以是一个方法、整个类,甚至可能是多个对象的组合(也许令人惊讶)。隔离意味着您可以以不同的顺序运行测试,也许可以并行运行,而不会影响另一个。

© www.soinside.com 2019 - 2024. All rights reserved.