部分考试科目:
class AddOptionsProviderArgumentPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if(!$container->hasDefinition('gremo_highcharts')) {
return;
}
if(!$container->hasParameter('gremo_highcharts.options_provider')) {
return;
}
// ...
}
}
我想断言:
hasDefinition()
使用参数'gremo_highcharts'调用将返回false
process()
返回,即不会调用其他方法一种解决方案是断言后续调用hasParameter()
:
public function testProcessWillReturnIfThereIsNoServiceDefinition()
{
$container = $this->getMockedContainerBuilder();
$pass = new AddOptionsProviderArgumentPass();
$container->expects($this->once())
->method('hasDefinition')
->with($this->equalTo('gremo_highcharts'))
->will($this->returnValue(false));
// Expects that hasParameter() is never invoked
$container->expects($this->never())
->method('hasParameter');
$pass->process($container);
}
但它似乎不是一个优雅的解决方案。
答案 0 :(得分:3)
要表达any method
,您可以使用$this->anything()
。
<?php
class fooTest extends PHPUnit_Framework_TestCase {
public function testNeverCallNothing() {
$mock = $this->getMock('mockMe');
$mock->expects($this->never())->method($this->anything());
//$mock->bar();
}
}
class mockMe {
public function bar() {}
}
输出:
PHPUnit 3.7.10-4-ga0bccf3 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 6.50Mb
OK (1 test, 1 assertion)
$mock->bar();
然后输出:
PHPUnit 3.7.10-4-ga0bccf3 by Sebastian Bergmann.
F
Time: 0 seconds, Memory: 6.50Mb
There was 1 failure:
1) fooTest::testNeverCallNothing
mockMe::bar() was not expected to be called.
.../tests/neverCallMe/fooTest.php:9
FAILURES!
Tests: 1, Assertions: 0, Failures: 1.
这看起来有点难看但也有效
<?php
class fooTest extends PHPUnit_Framework_TestCase {
public function testNeverCallNothing() {
$mock = $this->getMock('mockMe');
$mock->expects($this->once())->method('foo');
$mock->expects($this->never())->method(
$this->logicalNot($this->matches('foo'))
);
$mock->foo();
//$mock->bar();
}
}
class mockMe {
public function bar() {}
public function foo() {}
}
作品。在其他方法中进行注释时,它会像上面那样失败。
如果想要允许调用多个方法,它会变得更加冗长:
$this->logicalNot(
$this->logicalOr(
$this->matches('foo'),
$this->matches('baz'),
$this->matches('buz')
)
)
答案 1 :(得分:2)
这是一个例外情况吗?如果是这样,您可以更改第一次返回(为什么还要返回无效?)到抛出特定的异常。然后使用PHPUnit验证是否实际捕获了该特定异常。
编辑: 还有Phake你可以在测试结束时写这样的东西:(类似于用PHPUnit模拟对象调用 - &gt; never())
Phake::verify($container, Phake::times(0))->hasParameter();
这会在存根方法调用和验证已调用方法(存根或不存在)之间产生区别。
答案 2 :(得分:1)
在测试此类方法时,请尝试全局了解。不要下降到if
和return
s的级别,将其提高。通过声明在return
之后没有进行其他调用,您真正测试的是PHP的本机语句,而不是您的方法的逻辑。这就像你不相信return
。接受我的话,在return
语句后,在该方法中没有执行任何操作:)
相反,测试你的方法的逻辑!
逻辑是什么?
嗯,根据您的代码,您有此课程AddOptionsProviderArgumentPass
及其process
方法。 pocess
方法采用ContainerBuilder
并以某种方式处理它。因此,您需要测试的是process
方法可以很好地完成工作。方法中的if
代表了一些需要满足的约束才能成功处理ContainerBuilder
。
您如何理解process
是否成功?
按其返回类型。
如果它没有返回任何内容怎么办?
检查其副作用。您对ContainerBuilder
所做的事情是什么。
所以,我就是这样看的。
/**
* @test
*/
public function shouldNotProcessWithoutHighcharts()
{
// Arrange
$container = $this->buildContainer();
$container->removeDefinition('gremo_highcharts');
$pass = new AddOptionsProviderArgumentPass();
// Act
$pass->process($container);
// Assert
$this->assertFalse($container->hasWhatYouNeedItToHaveAfterProcessing())
}
/**
* @test
*/
public function shouldNotProcessWithoutHighchartsOptionsProvider()
{
// Arrange
$container = $this->buildContainer();
$container->getParameterBag()->remove('gremo_highcharts.options_provider');
$pass = new AddOptionsProviderArgumentPass();
// Act
$pass->process($container);
// Assert
$this->assertFalse($container->hasWhatYouNeedItToHaveAfterProcessing())
}
private function buildContainer()
{
$container = new ContainerBuilder();
$container->setParameter('gremo_highcharts.options_provider');
$container->setDefinition('gremo_highcharts');
return $container;
}
最后一点
不要依赖if
的顺序,它可以改变!
答案 3 :(得分:0)
也许创建Phake模拟并调用
Phake::verifyNoInteraction($mock);
是解决此问题的好方法。这是手册的链接:https://phake.readthedocs.io/en/2.1/method-verification.html#verifying-no-interaction-with-a-mock-so-far。