Unit testing 调用了模拟函数,但预期($this->;once())失败

Unit testing 调用了模拟函数,但预期($this->;once())失败,unit-testing,symfony,mocking,phpunit,Unit Testing,Symfony,Mocking,Phpunit,我正在测试一个Symfony命令来发送提醒短信。为此,我为我的文本消息接口创建了一个服务,并模拟了容器和文本消息服务: 正在测试的功能 protected function textReminders() { $mailer = $this->getContainer()->get('mailer'); $em = $this->getContainer()->get( 'doctrine' )->getManager(); if ($t

我正在测试一个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' )
            ;

}
测试

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' )
    ;
}
public function testExecute()
{
$insertSql='echo''
.str_替换(
数组(“,”`'),
数组(“\\”,“\\`'),
$this->getPrepSql())
“| mysql ahp_example_com”;
exec($insertSql);
self::引导内核();
$mockText=$this->getMockBuilder('TextaHQ')
->disableOriginalConstructor()
->setMethods(数组('sendSMS'))
->getMock();
$mockContainer=$this->getMockBuilder('Symfony\Component\DependencyInjection\Container'))
->disableOriginalConstructor()
->setMethods(数组('get'))
->getMock();
$container=self::$kernel->getContainer();
$mockContainer->method('get')
->连续(['mailer']、['doctrine']、['kernel']、['text_messaging.interface']))
->将返回执行调用(
$this->returnValue($container->get('mailer')),
$this->returnValue($container->get('doctrine')),
$this->returnValue(self::$kernel),
$this->returnValue($mockText))
;
$application=新应用程序(self:$kernel);
$application->add(新的actionememendmentcommand());
$mailer=self::$kernel->getContainer()->get('swiftmailer.mailer');
$logger=new\Swift\u Plugins\u MessageLogger();
$mailer->registerPlugin($logger);
$this->setMailCollector($logger);
$output='';
对于($i=1;$igetRunNoTimes();$i++){
$command=$application->find('ahp:remind');
$command->setContainer($mockContainer);
$commandTester=新commandTester($command);
$commandTester->执行(数组)(
'command'=>$command->getName(),
'键入'=>'文本'
) );
$output.=$commandTester->getDisplay();
}
$mockText
->预期($this->once())
->方法('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
/usr/bin/php/home/jochen/projects/ahp/trunk/vendor/phpunit/phpunit/phpunit--configuration/home/jochen/projects/ahp/trunk/app/phpunit.xml.dist agrichealth\AhpBundle\Tests\Command\actionmembrandvet7天前重新测试/home/jochen/projects/ahp/trunk/src/AgriHealth/AhpBundle/Tests/Command/rementtext/actionrementcommandvet7daysbeforetest.php——teamcity
测试于上午10:25开始。。。
PHPUnit 5.5.4由塞巴斯蒂安·伯格曼和贡献者撰写。
调用1次时,方法名称等于的预期失败。
方法应被调用1次,实际调用0次。
时间:1.12秒,内存:18.00MB
失败!
测试:1,断言:1,失败:1。
进程已完成,退出代码为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.
调用1次时,方法名称等于的预期失败。 方法应被调用1次,实际调用0次。
调试器将模拟的函数显示为小写:“sendsms”,但重命名该函数没有帮助。

下面是一个小的虚幻案例,以澄清我在评论中提到的要点。此外,对于在方法的实际调用执行后设置期望值的情况,它还有一个失败的测试(这看起来是一个多功能方法更新测试的情况)

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

顺便说一句,我想我第一次对你的代码研究得不够透彻。我想我可能误解了你的
setupmock
getMyMock
是如何工作的。对此我深表歉意。

看起来你的模拟配置超出了
testExecute
的范围。这意味着你不能通过
$t隐藏你的模拟his->setMyMock()
并在以后使用
$this->getMyMock()将其解压缩
用于断言。PHPUnit将无法跟踪调用。更多详细信息:我这样做是为了集中创建模拟对象和一组测试的测试执行。每个测试只有输入数据和结果更改。这是不可能的。我必须反复重复吗?更准确地说,你可以创建inst在
testMethod
之外对模拟对象进行一些常规配置,但所有的表达式都必须在
testMethod
内部定义。这是因为PHPUnit将这些期望绑定到此
testMethod
(当调用
testMethod
时,所有的期望值都被注册为该方法的期望值)。谢谢@xmike,我现在已经将所有内容都放在一个脚本中,它仍然不起作用。还有其他想法吗?如果我理解正确,我的测试范围是一个类