我尝试模拟一个php final class,但由于它被声明为final,我一直收到这个错误: PHPUnit_Framework_Exception: Class "Doctrine\ORM\Query" is declared "final" and cannot be mocked. 是否有办法在不引入任何新框架的情况下,仅针对我的单元测试来解决这个final行为?
<?php
final class Test {}
/** ZEND_ACC_CLASS is defined as 0, just looks nicer ... **/
uopz_flags(Test::class, null, ZEND_ACC_CLASS);
$reflector = new ReflectionClass(Test::class);
var_dump($reflector->isFinal());
?>
<?php declare(strict_types=1);
use DG\BypassFinals;
use PHPUnit\Runner\BeforeTestHook;
final class BypassFinalHook implements BeforeTestHook
{
public function executeBeforeTest(string $test): void
{
BypassFinals::enable();
}
}
public function someFunction()
{
// EntityManager was injected in the class
$query = $this->entityManager
->createQuery('SELECT t FROM Test t')
->setMaxResults(1);
$result = $query->getOneOrNullResult();
...
}
9条答案
按热度按时间kqhtkvqz1#
既然您提到您不想使用任何其他框架,那么您只剩下一个选择:uopz
uopz是runkit和scary-stuff类型的一个黑魔法扩展,旨在帮助QA基础设施。
uopz_flags是一个可以修改函数、方法和类的标志的函数。
将屈服
aiqt4smr2#
对于正在寻找这一特定学说查询模拟答案的人。
您不能模拟Doctrine\ORM\Query,因为它的“final”声明,但是如果您查看Query类代码,那么您将看到它是对AbstractQuery类的扩展,模拟它应该没有任何问题。
pinkon5k3#
有一个小型库Bypass Finals正是用于此目的,详细描述见blog post。
您只需在加载类之前启用此实用程序:
wvt8vs2t4#
我建议您看一看mockery testing framework,它有页面中描述的这种情况的解决方案:Dealing with Final Classes/Methods:
您可以通过将您希望模拟的示例化对象传递到\Mockery::mock()来创建代理模拟,即Mockery随后将生成一个真实对象的代理,并选择性地拦截方法调用,以便设置和满足预期。
作为示例,这允许执行类似以下操作:
我不知道你需要做什么,但我希望这能帮上忙
juzqafwq5#
当您想要模拟最后一个类时,现在正是使用Dependency inversion principle的最佳时机:
我们应该依靠抽象,而不是具体。
对于嘲笑它的意思是:创建一个抽象(接口或抽象类)并将其分配给最终类,然后模拟该抽象。
k75qkfdt6#
PHPUnit的2019年答案
我看到你用的是PHPUnit,你可以用bypass finals from this answer。
设置只比
bootstrap.php
多一点。阅读How to Mock Final Classes in PHPUnit中的“为什么”。下面是“怎么样”↓
2步
您需要使用Hook和旁路调用:
更新
phpunit.xml
:然后你可以模拟任何最终类:
cbeh67ev7#
我在
Doctrine\ORM\Query
上偶然发现了同样的问题,我需要对下面的代码进行单元测试:createQuery
返回Doctrine\ORM\Query
对象。我不能用Doctrine\ORM\AbstractQuery
来模拟,因为它没有setMaxResults
方法,而且我不想引入任何其他框架。为了克服final
对类的限制,我在PHP 7中使用了anonymous classes,它非常容易创建。在我的测试用例类中,我有:在我的测试中:
jaxagkaj8#
搞笑方式:)
PHP7.1、PHP5.7单元
zkure5ic9#
我已经实现了@Vadym方法并更新了它。现在我成功地使用它进行了测试!