6

代码将解释一切:

<?php

class ATest extends PHPUnit_Framework_TestCase
{
    public function testDestructorOnOriginalClass() {
        $a = new A();                                             // It
        unset($a);                                                // works
        echo " great!";                                           // great!
        $this->expectOutputString('It works great!');
    }

    public function testDestructorOnMockedClass() {
        $a = $this->getMock('A', array('someNonExistingMethod')); // It
        unset($a);                                                // works
        echo " great!";                                           // great!
        $this->expectOutputString('It works great!');
    }
}

class A {
    public function __construct()
    {
        echo "It";
    }

    public function __destruct()
    {
        echo " works";
    }
}

和输出:

# phpunit ATest.php 
PHPUnit 3.7.13 by Sebastian Bergmann.

.F

Time: 0 seconds, Memory: 3.50Mb

There was 1 failure:

1) ATest::testDestructorOnMockedClass
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'It works great!'
+'It great! works'


FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

正如您在第二个测试中看到的那样,它works以错误的顺序打印,可能是因为 phpunit 在某处存储对模拟的引用并__destruct()在测试结束时调用...好吧,我已经检查了getMock()方法,实际上它存储了对模拟对象的引用($this->mockObjects[] = $mockObject;)有效地阻止对象被破坏,因此__destructor()永远不会被调用。

/**
 * Returns a mock object for the specified class.
 *
 * @param  string  $originalClassName
 * @param  array   $methods
 * @param  array   $arguments
 * @param  string  $mockClassName
 * @param  boolean $callOriginalConstructor
 * @param  boolean $callOriginalClone
 * @param  boolean $callAutoload
 * @param  boolean $cloneArguments
 * @return PHPUnit_Framework_MockObject_MockObject
 * @throws PHPUnit_Framework_Exception
 * @since  Method available since Release 3.0.0
 */
public function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = FALSE)
{
    $mockObject = PHPUnit_Framework_MockObject_Generator::getMock(
      $originalClassName,
      $methods,
      $arguments,
      $mockClassName,
      $callOriginalConstructor,
      $callOriginalClone,
      $callAutoload,
      $cloneArguments
    );

    $this->mockObjects[] = $mockObject;

    return $mockObject;
}

所以问题是 - 有没有办法防止这种情况发生?忽略__destruct()何时应该调用它是我认为不好的限制。

4

3 回答 3

2

问题是当您不将任何值传递给“ getMock”方法的第二个参数时,PHPUnit 将存根您正在模拟的类中的所有方法(包括“ __destruct”)。

但是,如果您指定了至少一种方法(甚至可能是不存在的方法),PHPUnit 将仅存根您在第二个参数中传递的这些方法。

因此,如果您想保留所有方法,但还想创建模拟,您应该这样做:

$mock = $this->getMock('A', array('someNonExistingMethod'));

如果您更改此行,您的测试应该通过。

于 2013-02-13T17:47:55.157 回答
1

您只是在取消设置局部变量 - 您并没有破坏对象本身。

该对象也由 PHPUnit 自己保存。所以仍然有一个参考,因此你unset()不会导致__destruct().

因此,当前的行为无法更改。在 phpunit 问题跟踪器中打开一个错误。

于 2013-02-13T17:26:03.420 回答
0

如果我们clone模拟对象和unset它,__destruct()则可以在测试期间调用克隆对象。它可以帮助您测试__destruct()

请注意,此方法不能阻止__destruct()在测试结束时调用原始模拟对象。

于 2017-08-13T10:52:46.613 回答