是否有可能使用 PHPUnit 模拟对象来调用一个神奇的 __call() 方法?
Posted
技术标签:
【中文标题】是否有可能使用 PHPUnit 模拟对象来调用一个神奇的 __call() 方法?【英文标题】:Is it possible, using PHPUnit mock objects, to expect a call to a magic __call() method? 【发布时间】:2011-09-06 19:55:52 【问题描述】:我在测试中有一个模拟对象。真正的对象 PageRepository 使用 __call() 实现了一个神奇的方法,因此如果您调用 $pageRepository->findOneByXXXX($value_of_field_XXXX),它将在数据库中搜索与该参数匹配的记录。
有没有办法模拟那个方法?
真正的方法调用看起来像这样:
$homepage = $pageRepository->findOneBySlug('homepage');
测试看起来像这样:
$mockPageRepository->expects($this->any())
->method('findOneBySlug')
->will($this->returnValue(new Page()));
但它不起作用——phpUnit 没有发现方法调用。让它看到方法的唯一方法是在 PageRepository 中显式定义方法。
【问题讨论】:
【参考方案1】:PHPUnit 的getMock()
接受第二个参数,一个包含要模拟的方法名称的数组。
如果您在此数组中包含方法名称,则模拟对象将包含具有该名称的方法,expects()
和朋友将使用该名称。
这甚至适用于未在“真实”类中定义的方法,因此类似以下的方法应该可以解决问题:
$mockPageRepository = $this->getMock('PageRepository', array('findOneBySlug'));
请记住,您必须明确包含任何其他也需要模拟的方法,因为只有数组中命名的方法是为模拟对象定义的。
【讨论】:
请注意,如果您需要通过模拟构建器执行复杂的操作(例如禁用原始构造函数),则必须显式调用setMethods()
,例如$this->getMockBuilder('ClassName')->setMethods(['findById'])->getMock();
因为 builder 上的 getMock()
不接受任何参数。【参考方案2】:
我找到了更好的方法来做到这一点。仍然不完美,但您不必手动指定所有模拟类方法,只需指定魔术方法:
$methods = get_class_methods(PageRepository::class);
$methods[] = 'findOneBySlug';
$pageRepositoryMock = $this->getMockBuilder(PageRepository::class)
->disableOriginalConstructor()
->disableOriginalClone()
->disableArgumentCloning()
->disallowMockingUnknownTypes()
->setMethods($methods)
->getMock();
【讨论】:
以上是关于是否有可能使用 PHPUnit 模拟对象来调用一个神奇的 __call() 方法?的主要内容,如果未能解决你的问题,请参考以下文章