7

部分测试对象:

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);
}

但这似乎不是一个优雅的解决方案。

4

4 回答 4

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')
    )
)
于 2012-12-19T21:09:12.713 回答
2

是特例吗?如果是这样,您可以将第一个返回(为什么仍然返回 void?)更改为抛出特定异常。然后使用 PHPUnit 来验证是否确实捕获了该特定异常。

编辑:同样使用 Phake,您可以在测试结束时编写类似这样的内容:(类似于使用 PHPUnit Mock Objects 调用 ->never())

Phake::verify($container, Phake::times(0))->hasParameter();

这在存根方法调用和验证方法(是否已存根)已被调用之间产生了区别。

于 2012-12-19T11:29:48.623 回答
1

在测试此类方法时,请尝试查看全局。不要下降到ifs和returns的水平,拿它更高。通过断言在 之后没有进行其他调用return,您真正测试的是 PHP 的本机语句,而不是您的方法的逻辑。就像你不信任returns。相信我的话,return在该方法中没有执行任何语句之后:)

相反,测试你的方法的逻辑!

逻辑是什么?

好吧,根据你的代码,你有这个类AddOptionsProviderArgumentPass和它的process方法。该pocess方法采用 aContainerBuilder并以某种方式对其进行处理。因此,您需要测试的是该process方法是否能很好地完成它的工作。您if在方法中的 s 表示需要满足一些约束才能成功处理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;
}

最后注

不要依赖ifs的顺序,它可以改变!

于 2012-12-20T06:34:07.540 回答
0

也许创建 Phake 模拟并调用

Phake::verifyNoInteraction($mock);

是解决这个问题的好方法。这是手册的链接:https ://phake.readthedocs.io/en/2.1/method-verification.html#verifying-no-interaction-with-a-mock-so-far 。

于 2019-01-03T13:54:55.273 回答