1

phpunitでコントローラーの機能テストを行う際に、DB書き込みを無効にしたいです。

Symfony2 のプロジェクトでは、phpunit を使用して、データベースに保存する API エンドポイントへの POST 呼び出しをテストします。これは機能し、FOSUser+をアクティブにするときに回帰の問題が発生しましたHWIOAuth

phpunit がダミー データをデータベースに書き込むのを避けるために、ここでは次のトリックを使用します。Doctrine を使用して Symfony2 でコントローラーをテストし、エンティティ マネージャーをモックしてから、モックされたサービスをテスト システムのコンテナーに挿入します。

$entityManagerMock->expects($this->once())->method('flush');このようにしてテストを実行すると、DB エンドポイントがモックされ、その質問と以下のコードで確認できるように、flush() が呼び出されることのみがテストされます。

これは以前は機能していました。

このテストでは緑色のバーが表示され、POST 呼び出しがテストされ、データベースにデータが保存されませんでした。

public function testPostCreatesIssue()
{
    $client = static::createClient();

    $entityManagerMock = $this->getMockBuilder( 'Doctrine\ORM\EntityManager' )
        ->setMethods( array( 'persist', 'flush' ) )
        ->disableOriginalConstructor()
        ->getMock();

    $entityManagerMock->expects( $this->once() )
        ->method( 'flush' );

    $client->getContainer()->set( 'doctrine.orm.default_entity_manager', $entityManagerMock );

    $postData = array
    (
        'title' => 'Issues controller test, post creates issue',
        'body' => 'The test tests that a post call' . PHP_EOL . 'creates a new issue' . PHP_EOL . 'in the database.' . PHP_EOL . 'UTF8: áéíóú àèìòù ñç',
        'pageUrl' => 'file://Xmontero/AntiqueCrayon/MainBundle/Tests/Controller/IssuesControllerTest.php'
    );
    $crawler = $client->request( 'POST', '/issues/', $postData );
    $response = $client->getResponse();

    $this->assertEquals( Response::HTTP_CREATED, $response->getStatusCode() );
    $this->assertEquals( 'application/json', $response->headers->get( 'content-type' ) );
}

その時点では、デフォルトのバンドルと自分のバンドルしかありませんでした。AppKernel.php

問題

これらのバンドルをアクティブ化すると、AppKernel.php

new FOS\UserBundle\FOSUserBundle(),
new HWI\Bundle\OAuthBundle\HWIOAuthBundle(),

構成後、上記でテストした POST を実行する ajax 呼び出しを含め、すべてがブラウザーで手動でテストして正しく動作します。そのコントローラーは、カーネルでこれらのバンドルをアクティブ化する前に機能していたため、FOSUser および HWIOAuth とは何の関係もありません。

しかし、手動テストが機能したにもかかわらず、自動テストCall to a member function getRepository() on a non-objectは私のコードの行ではなく、FOS と Doctrine の内部で失敗し始めました-ここに完全な出力があります:

xavi@bromo:/files/custom_www/antique-crayon/preproduction$ phpunit -c app --filter Post src/Xmontero/AntiqueCrayon/MainBundle/Tests/Controller/IssuesControllerTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /files/custom_www/antique-crayon/preproduction/app/phpunit.xml.dist

PHP Fatal error:  Call to a member function getRepository() on a non-object in /files/custom_www/antique-crayon/preproduction/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php on line 759
PHP Stack trace:
PHP   1. {main}() /usr/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:46
PHP   3. PHPUnit_TextUI_Command->run() /usr/share/php/PHPUnit/TextUI/Command.php:130
PHP   4. PHPUnit_TextUI_TestRunner->doRun() /usr/share/php/PHPUnit/TextUI/Command.php:192
PHP   5. PHPUnit_Framework_TestSuite->run() /usr/share/php/PHPUnit/TextUI/TestRunner.php:325
PHP   6. PHPUnit_Framework_TestSuite->runTest() /usr/share/php/PHPUnit/Framework/TestSuite.php:745
PHP   7. PHPUnit_Framework_TestCase->run() /usr/share/php/PHPUnit/Framework/TestSuite.php:772
PHP   8. PHPUnit_Framework_TestResult->run() /usr/share/php/PHPUnit/Framework/TestCase.php:751
PHP   9. PHPUnit_Framework_TestCase->runBare() /usr/share/php/PHPUnit/Framework/TestResult.php:649
PHP  10. PHPUnit_Framework_TestCase->runTest() /usr/share/php/PHPUnit/Framework/TestCase.php:804
PHP  11. ReflectionMethod->invokeArgs() /usr/share/php/PHPUnit/Framework/TestCase.php:942
PHP  12. Xmontero\AntiqueCrayon\MainBundle\Tests\Controller\IssuesControllerTest->testPostCreatesIssue() /files/custom_www/antique-crayon/preproduction/src/Xmontero/AntiqueCrayon/MainBundle/Tests/Controller/IssuesControllerTest.php:0
PHP  13. Symfony\Component\BrowserKit\Client->request() /files/custom_www/antique-crayon/preproduction/src/Xmontero/AntiqueCrayon/MainBundle/Tests/Controller/IssuesControllerTest.php:41
PHP  14. Symfony\Bundle\FrameworkBundle\Client->doRequest() /files/custom_www/antique-crayon/preproduction/vendor/symfony/symfony/src/Symfony/Component/BrowserKit/Client.php:327
PHP  15. Symfony\Component\HttpKernel\Client->doRequest() /files/custom_www/antique-crayon/preproduction/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Client.php:111
PHP  16. Symfony\Component\HttpKernel\Kernel->handle() /files/custom_www/antique-crayon/preproduction/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Client.php:81
PHP  17. Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel->handle() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2330
PHP  18. Symfony\Component\HttpKernel\HttpKernel->handle() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:3080
PHP  19. Symfony\Component\HttpKernel\HttpKernel->handleRaw() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2931
PHP  20. Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2958
PHP  21. Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->preProcess() /files/custom_www/antique-crayon/preproduction/vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php:107
PHP  22. Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher->getListeners() /files/custom_www/antique-crayon/preproduction/vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php:215
PHP  23. Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher->lazyLoad() /files/custom_www/antique-crayon/preproduction/vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php:128
PHP  24. Symfony\Component\DependencyInjection\Container->get() /files/custom_www/antique-crayon/preproduction/vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php:188
PHP  25. appTestDebugProjectContainer->getProfilerListenerService() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2056
PHP  26. Symfony\Component\DependencyInjection\Container->get() /files/custom_www/antique-crayon/preproduction/app/cache/test/appTestDebugProjectContainer.php:2251
PHP  27. appTestDebugProjectContainer->getProfilerService() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2056
PHP  28. Symfony\Component\DependencyInjection\Container->get() /files/custom_www/antique-crayon/preproduction/app/cache/test/appTestDebugProjectContainer.php:2234
PHP  29. appTestDebugProjectContainer->getSecurity_ContextService() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2056
PHP  30. Symfony\Component\DependencyInjection\Container->get() /files/custom_www/antique-crayon/preproduction/app/cache/test/appTestDebugProjectContainer.php:2374
PHP  31. appTestDebugProjectContainer->getSecurity_Authentication_ManagerService() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2056
PHP  32. Symfony\Component\DependencyInjection\Container->get() /files/custom_www/antique-crayon/preproduction/app/cache/test/appTestDebugProjectContainer.php:3941
PHP  33. appTestDebugProjectContainer->getFosUser_UserProvider_UsernameEmailService() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2056
PHP  34. Symfony\Component\DependencyInjection\Container->get() /files/custom_www/antique-crayon/preproduction/app/cache/test/appTestDebugProjectContainer.php:3885
PHP  35. appTestDebugProjectContainer->getFosUser_UserManagerService() /files/custom_www/antique-crayon/preproduction/app/bootstrap.php.cache:2056
PHP  36. FOS\UserBundle\Doctrine\UserManager->__construct() /files/custom_www/antique-crayon/preproduction/app/cache/test/appTestDebugProjectContainer.php:1657
PHP  37. Doctrine\ORM\EntityManager->getRepository() /files/custom_www/antique-crayon/preproduction/vendor/friendsofsymfony/user-bundle/FOS/UserBundle/Doctrine/UserManager.php:40
xavi@bromo:/files/custom_www/antique-crayon/preproduction$

問題の絞り込み

問題はdoctrine.orm.default_entity_manager、テスト段階でモックを挿入するサービスです。これが、ブラウザーでの手動テストが失敗しない理由です。モックはありません。

モックを使用せずに実際の DB に書き込むようにテストを編集すると、次のように動作します。

->set()モックなしでテストするには、コンテナー内の をコメントアウトするだけです。Method was expected to be called 1 times, actually called 0 times.そして、私もコメントアウトを避けるために->expects()

    //$entityManagerMock->expects( $this->once() )
    //  ->method( 'flush' );
    //
    //$client->getContainer()->set( 'doctrine.orm.default_entity_manager', $entityManagerMock );

次に、テストの緑色のバー:

xavi@bromo:/files/custom_www/antique-crayon/preproduction$ phpunit -c app --filter Post src/Xmontero/AntiqueCrayon/MainBundle/Tests/Controller/IssuesControllerTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /files/custom_www/antique-crayon/preproduction/app/phpunit.xml.dist

.

Time: 0 seconds, Memory: 32.50Mb

OK (1 test, 2 assertions)
xavi@bromo:/files/custom_www/antique-crayon/preproduction$

結論

  • doctrine.orm.default_entity_managerFOSUser と HWIOAuthを事前にアクティブ化する際にモックを挿入すると、正常に動作します
  • トリックでこれらのバンドルを有効にするとAppKernel、機能しません。
  • 次に、実際のデータをデータベースに書き込むことを許可することしかテストできませんが、これはテスト時には望ましくありません。

質問

FOSUserBundle と HWIOAuthBundle がカーネルでアクティブ化されている場合、phpunit のテストからコントローラーを呼び出すときに、DataBase への書き込みを無効にするにはどうすればよいですか?

ありがとう!シャビ。

4

1 に答える 1