是否有相当于 SimpleTest 的“部分模拟”? 在 PHPUnit 中?
我正在尝试将一堆测试从 SimpleTest 迁移到 PHPUnit 我想知道是否有相当于 SimpleTest 的 部分模拟。
我似乎在文档中找不到任何表明此功能可用的内容,但我突然想到我可以只使用一个子类。 这是好主意还是坏主意?
class StuffDoer {
protected function doesLongRunningThing() {
sleep(10);
return "stuff";
}
public function doStuff() {
return $this->doesLongRunningThing();
}
}
class StuffDoerTest {
protected function doesLongRunningThing() {
return "test stuff";
}
}
class StuffDoerTestCase extends PHPUnit_Framework_TestCase {
public function testStuffDoer() {
$sd = new StuffDoerTest();
$result = $sd->doStuff();
$this->assertEquals($result, "test stuff");
}
}
I'm trying to migrate a bunch of tests from SimpleTest to PHPUnit and I was wondering if there is an equivalent for SimpleTest's partial mocks.
I can't seem to find anything in the documentation which suggests that this feature is available, but it occurred to me that I could just use a subclass. Is this a good or bad idea?
class StuffDoer {
protected function doesLongRunningThing() {
sleep(10);
return "stuff";
}
public function doStuff() {
return $this->doesLongRunningThing();
}
}
class StuffDoerTest {
protected function doesLongRunningThing() {
return "test stuff";
}
}
class StuffDoerTestCase extends PHPUnit_Framework_TestCase {
public function testStuffDoer() {
$sd = new StuffDoerTest();
$result = $sd->doStuff();
$this->assertEquals($result, "test stuff");
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
PHPUnit < 5.4
从阅读链接页面来看,SimpleTest 部分模拟似乎是仅覆盖部分方法的模拟。 如果这是正确的,则该功能由普通的 PHPUnit 模拟处理。
在
PHPUnit_Framework_TestCase
内,您创建一个模拟,它会创建一个模拟实例,其中所有方法都不执行任何操作并返回 null。 如果您只想重写某些方法,
getMock
的第二个参数是要重写的方法数组。将创建一个
Class_To_Mock
的模拟实例,并删除insert
和update
函数,准备好指定它们的返回值。此信息位于 phpunit 文档。
注意,此答案显示了更多最新的代码示例,适用于从 5.4 开始的 PHPUnit 版本
PHPUnit < 5.4
From reading the linked page, a SimpleTest partial mock seems to be a mock where only some of the methods are overridden. If this is correct, that functionality is handled by a normal PHPUnit mock.
Inside a
PHPUnit_Framework_TestCase
, you create a mock withWhich creates an mock instance where all methods do nothing and return null. If you want to only override some of the methods, the second parameter to
getMock
is an array of methods to override.will create an mock instance of
Class_To_Mock
with theinsert
andupdate
functions removed, ready for their return values to be specified.This information is in the phpunit docs.
Note, this answer shows more up to date code examples, for PHPUnit versions starting 5.4
PHPUnit 5.4 到 7
PHPUnit_Framework_TestCase::getMock
是自 phpunit 5.4 起已弃用。 我们可以使用setMethods
来代替。https://phpunit.de/manual/current/en/test-doubles。 html
注意,上面的
getMock
是PHPUnit_Framework_MockObject_MockBuilder::getMock
。 (phpunit5.6)PHPUnit 5.4 to 7
PHPUnit_Framework_TestCase::getMock
is deprecated since phpunit 5.4. We can usesetMethods
instead.https://phpunit.de/manual/current/en/test-doubles.html
Note that the above
getMock
isPHPUnit_Framework_MockObject_MockBuilder::getMock
. (phpunit5.6)PHPUnit 8+
方法
setMethods
已弃用。 现在它可以工作了:PHPUnit 8+
The method
setMethods
was deprecated. Now it works:我认为 PHPUnit 不支持对被测系统的部分模拟。 如果您尝试隔离方法,那么我确信您的实现是有效的 - 我也这样做了。
然而,出于几个原因,我尽量避免这样做。
首先,它将您的测试与类的内部实现紧密结合。 您真的关心是否调用了名为
doesLongRunningThing
的方法,还是“LongRunningThing”完成更重要?其次,当我遇到这个问题时,我总是想知道是否有一个班级做两个班级的工作。 提取类重构可能是合适的。 如果
doesLongRunningThing()
成为自己的类,即使使用单个方法,测试也会变得更加容易。我相信解决方案是注入 SUT 所依赖的服务 (http://en.wikipedia.org/wiki/Dependency_injection)。 这也使得
DoesLongRunningThing
实现更易于测试。在不跳入界面的情况下,我会这样做:
现在很容易模拟:
I don't think PHPUnit supports partial mocks for the system under test. If you're trying to isolate methods then I'm sure your implementation works - I've done that too.
However, I try to avoid doing this, for a couple of reasons.
First, it couples your test very tightly to the internal implementation of the class. Do you really care whether a method called
doesLongRunningThing
was called, or is it more important that the "LongRunningThing" got done?Second, when I run into this it always makes me wonder whether I've got one class doing the job of two. An extract class refactoring might be in order. The testing becomes much easier if
doesLongRunningThing()
becomes its own class, even with a single method.I believe the solution is to inject the services your SUT depends on (http://en.wikipedia.org/wiki/Dependency_injection). This also makes the
DoesLongRunningThing
implementation more testable.Without jumping into interfaces, here's what I would do:
Now it's easy to mock:
可能是您正在嘲笑的类不在范围内(我遇到了这个问题)。 解决后,我能够模拟一个函数并测试另一个函数的实际逻辑。
It could be that the class you are mocking is not in scope (I had this issue). When resolved, I was able to mock one function and test the actual logic of another.