2016-11-15 4 views
0

Ich teste einen Symfony-Befehl, um Erinnerung Textnachrichten zu senden. Dafür habe ich einen Dienst für meine SMS-Schnittstelle und bin spöttisch den Behälter sowie den Text-Messaging-Dienst erstellt:

Die Funktion im Test

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

} 

-Test

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

} 

Aktualisierter Test, alles in einer Datei

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 Testanruf **

/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 

Wenn ich den Test debuggen, kann ich sehen, dass $ Textm ein Mock ist.

jedoch am Ende des Tests in Behauptungen(), erhalte ich eine Fehlermeldung:

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. 

Der Debugger zeigt die verspottete Funktion als Kleinbuchstaben: „sendsms“, aber die Funktion Umbenennung hat nicht geholfen.

+0

sieht aus wie Ihre Mock-Konfiguration fällt aus 'testExecute' Bereich bedeutet, dass Sie Ihre Mocks nicht über '$ this-> setMyMock()' speichern und später mit '$ this-> getMyMock()' für die Assertion extrahieren können. PHPUnit kann die Aufrufe nicht verfolgen. Weitere Details: [Nur Mock-Objekte erzeugt im Rahmen eines Tests wird von PHPUnit automatisch verifiziert.] (https://phpunit.de/manual/current/en/test-doubles.html#test-doubles.mock-objects) – xmike

+0

Ich habe es so gemacht Möglichkeit, die Erstellung der Mock-Objekte zu zentralisieren und die Ausführung für eine Gruppe von Tests zu testen. Nur die Eingabedaten und das Ergebnis ändern sich für jeden Test. Ist das nicht möglich? Muss ich es immer wieder wiederholen? – jdog

+1

um genauer zu sein: Sie können Instanzen Ihrer Mock-Objekte erstellen und einige allgemeine Konfigurationen außerhalb von 'testMethod' vornehmen, aber alle Erwartungen müssen innerhalb von' testMethod' definiert werden. Das liegt daran, dass PHPUnit solche Erwartungen an diese 'testMethod' bindet (wenn' testMethod' aufgerufen wird, werden alle Erwartungen für diese Methode als erwartet registriert). – xmike

Antwort

1

Hier ist ein kleiner illustrativer Fall, um die Punkte zu klären, die ich in Kommentaren erwähnt habe. Auch sie hat einen versagende Test für die Situation, wenn die Erwartungen gesetzt werden, nachdem actuall Ruf nach dem Verfahren durchgeführt wurde (was der Fall des All-In-One-Methode Update-Tests aussieht.

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 ich denke, Ich habe Ihren Code nicht gründlich genug zum ersten Mal untersucht. Ich glaube, ich könnte es vermissen, wie Ihre setupMocks und getMyMock funktionieren sollte. Entschuldigung.

Verwandte Themen