PHPUnit:现有对象的模拟方法

cwe*_*ske 17 php phpunit mocking object

PHPUnit getMock($classname, $mockmethods)根据给定的类名创建一个新对象,让我更改/测试我指定的方法的行为.

我渴望一些不同的东西; 它正在改变现有对象方法的行为 - 无需构建新对象.

那可能吗?如果有,怎么样?


在考虑问题时,我得出的结论是,通过序列化对象,更改序列化字符串以使对象成为扩展旧类加上模拟方法的新类的实例是可能的.我想要一些代码 - 或者可能已经存在某些代码.


虽然再次创建被模拟对象肯定是可能的,但在我的测试中这样做太复杂了.因此,如果我真的不需要,我不想这样做.这是一个TYPO3 TSFE实例,并且在引导过程中设置一次已经足够困难了.

edo*_*ian 10

让我首先说:欢迎来到单元测试的黑暗面.

含义:您通常不想这样做,但正如您所解释的那样,您有一个看似有效的用例.

runkit

你可以很容易地做到这一点,而不是简单但比改变应用程序架构更容易,就是使用runkit动态改变类行为

runkit_method_rename(
    get_class($object), 'methodToMock', 'methodToMock_old'
);
runkit_method_add(
    get_class($object), 'methodToMock', '$param1, $param2', 'return 7;'
);
Run Code Online (Sandbox Code Playgroud)

runkit :: method_add

并在测试完一个method_remove后重新命名.我不知道任何可以帮助你的框架/组件,但是你自己实现的并不是那么多UglyTestsBaseTest extends PHPUnit_Framework_TestCase.

好...

如果你有权访问的是对该对象的引用(如:$xin $x = new Foo();),我不知道如何说:$ x,你现在是类型SomethingElse,指向该对象的所有其他变量也应该改变.

我将假设您已经知道测试您的私有部分,但它对您没有帮助,因为您无法控制对象的生命周期.

php测试助手扩展

注: 该试验助手扩展取代https://github.com/krakjoe/uopz

也可以帮助你的是:使用php-test-helpers扩展来存储硬编码依赖关系,允许你做拦截对象创建之类的事情.

这意味着当你的应用程序调用时,$x = new Something();你可以破解PHP来制作它,$x然后包含一个实例YourSpecialCraftedSomething.

您可以使用PHPUnit Mocking API创建该分类,也可以自己编写.


据我所知,这些是你的选择.如果它值得去那里(或者只是为该项目编写集成/硒测试)是你必须自己解决的问题,因为它在很大程度上取决于你的情况.


Bai*_*ker 10

我知道这个答案已经很晚了,但我觉得对于这个问题的未来观众现在存在一个更简单的解决方案(它有一些缺点,但根据你的需要可以更容易实现).Mockery支持使用他们称之为"代理部分模拟"的模拟预先存在的对象.他们说这是针对具有最终方法的类,但是在这种情况下可以使用它(尽管文档提醒它应该是"最后的手段").

$existingObjectMock = \Mockery::mock($existingObject);
$existingObjectMock->shouldReceive('someAction')->andReturn('foobar');
Run Code Online (Sandbox Code Playgroud)

它的作用是创建一个代理对象,该对象将所有方法调用和属性获取/设置传递给现有对象,除非它们被模拟.

但应该注意的是,代理遭受了任何类型检查或类型提示失败的明显问题.但这通常可以避免,因为$existingObject仍然可以传播.您应该只$existingObjectMock在需要模拟功能时使用.


Pau*_*ulC 6

并非所有预先存在的代码都可以进行测试.代码确实需要设计为可测试的.因此,虽然不完全是您所要求的,但您可以重构代码,以便对象的实例化在一个单独的方法中,然后模拟该方法以返回您想要的内容.

class foo {
  function new_bar($arg) { return new bar($arg); }
  function blah() {
    ...
    $obj = $this->new_bar($arg);
    return $obj->twiddle();
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以测试它

class foo_Test extends PHPUnit_Framework_TestCase {
  function test_blah() {
    $sut = $this->getMock('foo', array('new_bar', 'twiddle'));
    $sut->expects($this->once())->method('new_bar')->will($this->returnSelf());
    $sut->expects($this->once())->method('twiddle')->will($this->returnValue('yes'));
    $this->assertEquals('yes', $sut->blah());
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么投票给这个答案?我发现完全可以理解的是,建议重构而不是做"让事情有效"的黑暗魔法 (2认同)