调用模拟函数,但期望($ this-> once())失败

时间:2016-11-15 22:19:50

标签: unit-testing symfony mocking phpunit

我正在测试Symfony命令以发送提醒短信。为此我已经为我的文本消息界面创建了一个服务,并且正在模拟容器以及文本消息服务:

正在测试的功能

protected function textReminders()
{
    $mailer = $this->getContainer()->get('mailer');
    $em = $this->getContainer()->get( 'doctrine' )->getManager();


    if ($this->getContainer()->get('kernel')->getEnvironment() == 'dev'){
        $debug = true;
    }else{
        $debug = false;
    }

    $textMessage = $this->getContainer()->get('text_messaging.interface');
    $textMessage->sendSMS( $target, $content, $debug);

}

测试

private function getMockContainer()
{
    $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\Container')
                      ->disableOriginalConstructor()
                      ->setMethods(array('get'))
                      ->getMock();

    return $container;
}

protected function setupMocks()
{
    $mockText = $this->getMockBuilder('TextaHQ')
                     ->disableOriginalConstructor()
                     ->setMethods(array('sendSMS'))
                     ->getMock();
    $mockContainer = $this->getMockContainer();

    $container = self::$kernel->getContainer();
    $mockContainer->method('get')
        ->withConsecutive(['mailer'], ['doctrine'], ['kernel'], ['text_messaging.interface'])
        ->willReturnOnConsecutiveCalls(
            $this->returnValue($container->get('mailer')),
            $this->returnValue($container->get('doctrine')),
            $this->returnValue(self::$kernel),
            $this->returnValue($mockText))
    ;

    $this->setMyMock([
                         'text' => $mockText,
                         'container' => $mockContainer
                     ]);
}

public function testExecute()
{
    $this->setupMocks();
    self::bootKernel();
    $application = new Application(self::$kernel);

    $application->add(new ActionRemindCommand());

    $command = $application->find( 'ahp:remind' );
    $command->setContainer($this->getMyMock()['container']);
    $commandTester = new CommandTester( $command );

    $commandTester->execute( array(
                                     'command' => $command->getName(),
                                     'type' => 'text'
                                 ) );
    $output = $commandTester->getDisplay();

    $this->assertions();
}

protected function assertions()
{
    $this->getMyMock()['text']
        ->expects( $this->once() )
            ->method( 'sendSMS' )
            ;

}

更新了测试,全部在一个文件中

public function testExecute()
{
    $insertSql = 'echo "'
        . str_replace(
            array('"'    ,'`'  ),
            array('\\"'  ,'\\`'),
            $this->getPrepSql() )
        . '" | mysql ahp_example_com';
    exec($insertSql);

    self::bootKernel();

    $mockText = $this->getMockBuilder('TextaHQ')
                     ->disableOriginalConstructor()
                     ->setMethods(array('sendSMS'))
                     ->getMock();
    $mockContainer = $this->getMockBuilder('Symfony\Component\DependencyInjection\Container')
                                       ->disableOriginalConstructor()
                                       ->setMethods(array('get'))
                                       ->getMock();

    $container = self::$kernel->getContainer();
    $mockContainer->method('get')
                  ->withConsecutive(['mailer'], ['doctrine'], ['kernel'], ['text_messaging.interface'])
                  ->willReturnOnConsecutiveCalls(
                      $this->returnValue($container->get('mailer')),
                      $this->returnValue($container->get('doctrine')),
                      $this->returnValue(self::$kernel),
                      $this->returnValue($mockText))
    ;


    $application = new Application(self::$kernel);

    $application->add(new ActionRemindCommand());

    $mailer = self::$kernel->getContainer()->get('swiftmailer.mailer');
    $logger = new \Swift_Plugins_MessageLogger();
    $mailer->registerPlugin( $logger );
    $this->setMailCollector($logger);

    $output = '';
    for($i=1;$i<=$this->getRunNoTimes();$i++) {
        $command = $application->find( 'ahp:remind' );
        $command->setContainer($mockContainer);
        $commandTester = new CommandTester( $command );

        $commandTester->execute( array(
                                     'command' => $command->getName(),
                                     'type' => 'text'
                                 ) );
        $output .= $commandTester->getDisplay();
    }

    $mockText
        ->expects( $this->once() )
        ->method( 'sendSMS' )
    ;
}

** PHPStorm测试电话**

/usr/bin/php     /home/jochen/projects/ahp/trunk/vendor/phpunit/phpunit/phpunit --configuration /home/jochen/projects/ahp/trunk/app/phpunit.xml.dist AgriHealth\AhpBundle\Tests\Command\ActionRemindCommandVet7DaysBeforeTest /home/jochen/projects/ahp/trunk/src/AgriHealth/AhpBundle/Tests/Command/RemindText/ActionRemindCommandVet7DaysBeforeTest.php --teamcity
Testing started at 10:25 AM ...
PHPUnit 5.5.4 by Sebastian Bergmann and contributors.


Expectation failed for method name is equal to <string:sendSMS> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.



Time: 1.12 seconds, Memory: 18.00MB


FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Process finished with exit code 1

当我调试测试时,我可以看到$ textMessage是一个模拟。

但是在assertions()测试结束时,我收到一个错误:

Expectation failed for method name is equal to <string:sendsms> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.

调试器将模拟函数显示为小写:“sendsms”,但重命名函数没有帮助。

1 个答案:

答案 0 :(得分:1)

这是一个小插图案例,以澄清我在评论中提到的观点。此外,对于在执行方法的执行调用之后设置了期望的情况(对于您的一体化方法更新测试的情况),它还有一个失败的测试情况。

class MyClass
{
    public function someMethod(){

    }
}

class ExpectationsTest extends PHPUnit_Framework_TestCase
{
    private $myClassMock;

    public function setUp(){
        $this->myClassMock = $this->getMock('MyClass');
    }

    public function testLocalMock(){
        $localMock = $this->getMock('MyClass');
        $localMock->expects($this->once())
                  ->method('someMethod');
        $localMock->someMethod();
    }

    public function testClassScopeMockInstance(){
        $this->myClassMock->expects($this->once())
                          ->method('someMethod');
        $this->myClassMock->someMethod();
    }

    public function testWillFailBecauseExpectationWasSetAfterCall(){
        $this->myClassMock->someMethod();
        $this->myClassMock->expects($this->once())
                          ->method('someMethod');
    }

    public function testCanUseHelperToCreateLocalMock(){
        $mock = $this->createMyClassMock();
        $mock->expects($this->once())
             ->method('someMethod');
        $mock->someMethod();
    }

        private function createMyClassMock(){
            return $this->getMock('MyClass');
        }

    public function testCanSetExpectationsInHelper(){
        $this->setExpecatationsOnTestCaseScopeMock();
        $this->myClassMock->someMethod();
    }

        private function setExpecatationsOnTestCaseScopeMock(){
            $this->myClassMock->expects($this->once())
                              ->method('someMethod');
        }
}

btw我想我第一次没有彻底探索你的代码。我想我可能会想到你的setupMocksgetMyMock是如何工作的。对不起。