phpunit对于那些刚刚学习PHP中编程和/或单元测试的基础知识的人来说可能是压倒性的。这是一种强大而健壮的工具,多年来一直是PHP世界中单元测试的基石,这意味着它具有一套巨大的功能,几乎涵盖了您可能遇到的任何情况。
Phpunit最有力的功能之一是stubs和mocks。它们使您能够从试图测试的部分分离代码的其余部分。您可以模拟任何内容 - 从您正在测试的类中的(其他)方法中,到依赖性,抽象类甚至特质和接口。
第一步,当然是在建立模拟,通常是这样的:
$serviceMock = $this->getMockBuilder(YourService::class)
->disableOriginalConstructor()
->onlyMethods(['anotherMethodInYourClass', 'yetAnotherMethod'])
->getMock();
除了上面示例中所示的方法之外,您还拥有许多其他方法,例如setConstructorArgs()
和setMethods()
,但是我们不会更深入地了解他们的工作。在我们的情况下,重要的是,您将如何确切地创建一个模拟对象,这取决于您的需求。您可能需要模拟一组依赖项,一个抽象类,接口,...
如果您仍在学习(或者即使您不跟上Phpunit版本之间的更改),则最终可能会“猜测”创建模拟时要调用哪种方法。甚至Stackoverflow都充满了答案,例如“ 为我为我创建模拟作品的下列方式” - 没有提供任何信息或上下文。
好吧,让我们提供一些上下文。
phpunit在引擎盖下,正在创建一个模拟班,就像您写任何课程一样。它为您试图模拟的类,性状或界面生成源代码,并用模拟的属性和返回值填充它。 PHPUNIT性能之一是生成的模拟类代码是有效的PHP代码。这是通过鲜为人知的内置PHP函数koude2完成的。此功能评估$someString
是否包含有效的PHP代码。但是,如官方文档所述,有些警告: eval()语言构造非常危险,因为它允许执行任意PHP代码。因此,它不建议使用。如果您已经仔细地验证了除了使用此构造之外没有其他选择,请特别注意不要将任何用户提供的数据传递到未经事先验证的情况下。
话虽如此,phpunit准备了生成的模拟类的源代码,并将其存储在字符串中,然后使用eval()
函数对其进行评估。
如果您在尝试创建或使用模拟时会遇到错误,则不确定引擎盖下的确切发生了什么以及生成的模拟类实际上是看起来像 - 有一种方法可以看到在调试期间,模拟类的实际内容(完整的源代码)。
要查看的关键点是PHPUnit\Framework\MockObject\MockClass
类及其generate()
方法。在phpunit 9.6中,它像这样:
public function generate(): string
{
if (!class_exists($this->mockName, false)) {
eval($this->classCode);
call_user_func(
[
$this->mockName,
'__phpunit_initConfigurableMethods',
],
...$this->configurableMethods
);
}
return $this->mockName;
}
如果在eval($this->classCode)
上设置了一个断点,则可以看到$this->classCode
的内容,显然,该内容包含生成的模拟类的完整源代码。最好的部分是 - 它甚至正确地格式化了,因此您不会遇到任何阅读的问题。
您现在可以自由地尝试使用不同类型的模拟和创建选项,同时查看创建模拟的方式的确切方式会影响最终结果 - 模拟的对象。玩得开心!