【问题标题】:Unit Test for Parent Method Call父方法调用的单元测试
【发布时间】:2018-04-20 06:45:56
【问题描述】:

奇怪的是,我不仅没有找到答案,而且这个问题似乎根本不是问题。但是,这是给我的。

如何使用 PHPUnit 设置对父方法调用的期望?

我已经阅读了答案和讨论,其中的重点是“您无需对此进行测试,您只需测试它是否有效”。这是完全错误的。单元测试用于测试实现的内部结构。测试“它有效”是为了功能测试。

更多上下文:我有一个异常实现,它接受构造函数的附加参数,因此自然需要调用parent::__construct()方法,将消息、代码和内部异常转发给它。我知道父方法有效,我不需要对其进行测试:它是一个原生 PHP 类,即使不是,该代码也不在我正在测试的类中。所以,我只需要设置一些期望,其中之一就是使用适当的参数调用父 __construct() 方法。当然,构造函数并不是唯一需要这样做的情况。

有什么想法吗?

【问题讨论】:

  • 单元测试用于测试实现的内部结构——通常情况并非如此。单元测试用于测试类的公共 API 的行为。不是它如何在内部实现这种行为。
  • 类的想法是,它们从“用户”中抽象出某些东西是如何实现的,因此您的单元测试通常应该只测试类的行为而不是实现方法。有像 assertAttributeContains() 这样的方法可以让您检查内部值,但要做好准备,当您更新任何依赖项时,您的测试可能会失败。

标签: php unit-testing mocking phpunit


【解决方案1】:

对于 PHPUnit 和检查父方法调用,不幸的是这是不可能的。您始终可以创建一个类的模拟并检查是否调用了父构造函数,但是您只是在测试一个模拟而不是您的实际类。这绝对不是你想要的。正如其他人已经在另一个答案中指出的那样:您不会模拟或存根被测对象 (https://stackoverflow.com/a/6711948/4737924)。

你是说你需要知道的是父构造函数被调用了。我认为这只是实现的技术细节。您真正需要知道的是您的异常是否按照它需要的方式运行。

看看下面的例子:

class MyException extends Exception
{
    private $somethingElse;

    public function __construct(string $message, int $code, Throwable $previousException, SomethingElse $somethingElse)
    {
        $message = $message . ' - my additional message';
        parent::__construct($message, $code, $previousException);

        $this->somethingElse = $somethingElse;
    }

    public function getSomethingElse(): SomethingElse
    {
        return $this->somethingElse;
    }
}

class MyExceptionTest extends TestCase
{
    public function testIsCreatedProperly(): void
    {
        $previousException = new Exception();
        $somethingElse = new SomethingElse();

        $exception = new MyException('My message', 100, $previousException, $somethingElse);

        $this->assertSame('My message -  my additional message', $exception->getMessage());
        $this->assertSame(100, $exception->getCode());
        $this->assertSame($previousException, $exception->getPrevious());
        $this->assertSame($somethingElse, $exception->getSomethingElse());
    }
}

这里只有行为很重要。消息是正确的,代码或先前的异常是如何发生的,这真的无关紧要。重要的是它是否按照您希望的方式运行。您不需要显式检查是否调用了父构造函数。你知道它被调用是因为输出符合预期。

【讨论】:

    【解决方案2】:

    您可以像以下 trait 一样创建 smth,并在所有需要模拟父方法调用的类中使用它:

    trait ParentCallTestable
    {
        /**
         * Call parent methdod
         * @param  string $method  Method name to call
         * @return mixed
         */
        public function parent($method, ...$args)
        {
            return parent::$method(...$args);
        }
    }
    

    然后在一个使用这个特性的类中,标准父调用

    $result = parent::fooMethod($arg1, $arg2);

    替换为

    $result = $this->parent('fooMethod', $arg1, $arg2);

    你可以轻松地模拟它。

    【讨论】:

    • 我最终使用了这种模式,但是对于特定方法,而不是通用方法。
    猜你喜欢
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 2011-12-03
    • 1970-01-01
    • 2022-04-01
    相关资源
    最近更新 更多