Dan*_*bib 28 php phpunit unit-testing mocking doctrine-orm
我试图模拟一个PHP final class但是因为它被声明final我一直收到这个错误:
PHPUnit_Framework_Exception: Class "Doctrine\ORM\Query" is declared "final" and cannot be mocked.
反正final是为了我的单元测试而不引入任何新框架来解决这种行为?
Joe*_*ins 14
既然你提到你不想使用任何其他框架,你只留下一个选择:uopz
uopz是runkit-and-scary-stuff类型的黑魔术扩展,旨在帮助QA基础设施.
uopz_flags是一个可以修改函数,方法和类的标志的函数.
<?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());
?>
Run Code Online (Sandbox Code Playgroud)
会屈服
bool(false)
Run Code Online (Sandbox Code Playgroud)
wor*_*hit 12
对于正在寻找此特定学说查询模拟答案的人的延迟回复.
你不能模仿Doctrine\ORM\Query,因为它的"最终"声明,但如果你查看Query类代码,那么你会看到它扩展的AbstractQuery类,并且不应该有任何问题嘲笑它.
/** @var \PHPUnit_Framework_MockObject_MockObject|AbstractQuery $queryMock */
$queryMock = $this
->getMockBuilder('Doctrine\ORM\AbstractQuery')
->disableOriginalConstructor()
->setMethods(['getResult'])
->getMockForAbstractClass();
Run Code Online (Sandbox Code Playgroud)
我建议你看看嘲讽测试框架,它有一个解决方法,可以解决页面中描述的这种情况:处理最终的类/方法:
您可以通过将您希望模拟的实例化对象传递到\ Mockery :: mock()来创建代理模拟,即Mockery将为真实对象生成代理并有选择地拦截方法调用以设置和满足期望.
例如,这允许做这样的事情:
class MockFinalClassTest extends \PHPUnit_Framework_TestCase {
public function testMock()
{
$em = \Mockery::mock("Doctrine\ORM\EntityManager");
$query = new Doctrine\ORM\Query($em);
$proxy = \Mockery::mock($query);
$this->assertNotNull($proxy);
$proxy->setMaxResults(4);
$this->assertEquals(4, $query->getMaxResults());
}
Run Code Online (Sandbox Code Playgroud)
我不知道你需要做什么,但我希望这有帮助
当你想模拟一个 final 类时,这是利用依赖倒置原则的最佳时机:
人们应该依赖抽象,而不是具体。
对于模拟,它意味着:创建一个抽象(接口或抽象类)并将其分配给最终类,并模拟抽象。
只需要做的就是在加载类之前启用此实用程序:
DG\BypassFinals::enable();
Run Code Online (Sandbox Code Playgroud)
我看到您正在使用 PHPUnit。您可以使用此答案中的绕过决赛。
设置只是多一点bootstrap.php。阅读如何在 PHPUnit 中模拟最终类中的“为什么” 。
这里是“如何”?
您需要将 Hook 与旁路呼叫一起使用:
<?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();
}
}
Run Code Online (Sandbox Code Playgroud)
更新phpunit.xml:
<phpunit bootstrap="vendor/autoload.php">
<extensions>
<extension class="Hook\BypassFinalHook"/>
</extensions>
</phpunit>
Run Code Online (Sandbox Code Playgroud)
然后你可以模拟任何最终课程: