为什么phpunit不会在模拟类中运行__destruct()以及如何强制它?

Kam*_*zic 6 php phpunit unit-testing destructor mocking

代码将解释一切:

<?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";
    }
}
Run Code Online (Sandbox Code Playgroud)

和输出:

# 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.
Run Code Online (Sandbox Code Playgroud)

正如您在第二次测试中看到的那样,它works以错误的顺序打印,可能是因为phpunit存储了对某个地方的模拟引用并__destruct()在测试结束时被调用...好的我已经检查过getMock()方法并确实存储了对mocked对象的引用($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;
}
Run Code Online (Sandbox Code Playgroud)

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

cwe*_*ske 1

您只是取消设置局部变量 - 您没有销毁对象本身。

该对象也由 PHPUnit 本身保存。所以仍然有一个引用,因此你的unset()不会导致__destruct().

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