1

doctrine またはその他の一般的なサービスを使用する symfony 2 サービスを単体テストする正しい方法を見つけるのに苦労しています。

私がこれまでに行ったこと:

  • 私の理解では、コントローラーのアクションは次のようにする必要があります。
    • できるだけ短くする
    • リクエストを受け取ります
    • 注入されたサービスから必要なメソッドを実行する
    • これから応答を作成する
    • サービスそのものです

軽量のアクションを実現するために、コントローラーに注入される別のサービスにロジックをカプセル化しようとしました。

これは、すべてをテストすることを期待してうまく機能します。

ここに私の現在のコード:

コントローラ

class SearchController
{   
    // search_helper, request and templating are controller-injected
    protected $search_helper;
    protected $request;
    protected $templating;

    // ...

    public function searchAction()
    {
        $searchterm = strtolower($this->request->query->get('q'));

        $result = $this->search_helper->findSamples($searchterm);

        // Found a single result. Redirect to this page
        if (is_string($result))
        {
            return new RedirectResponse($result, 301);
        }

        return new Response($this->templating->render('AlbiSampleBundle:Search:index.html.twig', array('results' => $result)));
    }
}

検索サービス

class SearchHelper
{
    // doctrine, session and min_query_len are controller-injected
    protected $doctrine;
    protected $session;
    protected $min_query_len;

    // ...

    public function findSamples($searchterm)
    {
        if (strlen($searchterm) < $this->min_query_len)
        {
            $msg = 'Your search must contain at least 3 characters!';
            $this->session->getFlashBag()->add('error', $msg);

            return false;
        }

        $em = $this->doctrine->getManager();
        $results = $em->getRepository('AlbiSampleBundle:Sample')->findPossibleSamples($searchterm);

        // Execute a more advanced search, if std. search don't delivers a result
        // ...

        return $results;
    }
}

このコードを正しくテストするにはどうすればよいですか?

  • リポジトリは phpunit_db とインメモリ sqlite データベースでテストされています ✓</li>
  • アクションは、簡単な機能テストでテストできます ✓</li>
  • 残っているのは検索サービスのロジックです。例: findSamples メソッド

私が最初に考えたのは、依存関係をモックすることでした (実際、依存関係を分離する際の主要な側面の 1 つでした) が、ドクトリン オブジェクトだけでなく、エンティティ マネージャーとリポジトリもモックする必要があります。

$em = $this->doctrine->getManager();
$results = $em->getRepository('AlbiSampleBundle:Sample')->findPossibleSamples($searchterm);

もっと良い解決策があるはずだと思います。このモックには多くの LOC が必要になるだけでなく、正しくないとも感じられます。テストは、不必要に SUT に非常に緊密に結合されます。

編集

これが私が思いついたサンプルテストです。モック オブジェクトの使用。テストはうまくいきません。もっと多くのモックオブジェクトが必要になることに気づき、これは正しい方法ではないと感じました。

SessionMock->getFlashbagメソッドでフラッシュバッグを返さないため、テストは失敗しますadddoctrine->getManagerいいえを返しますEntityManager。には方法EntityManagerがありませんgetRepository。また、リポジトリがありませんfindPossibleSamples

class SearchHelperTest extends \PHPUnit_Framework_TestCase
{
    private $router;
    private $session;
    private $doctrine;

    public function setUp()
    {       
        parent::setUp();

        // ...
    }

    public function testSearchReturnValue()
    {
        $search_service = $this->createSearchHelper();
        $this->assertFalse($search_service->findSamples('s'));
    }

    protected function createSearchHelper()
    {
        return new SearchHelper($this->doctrine, $this->router, $this->session, 3);
    }

    protected function getDoctrineMock()
    {
        return $this->getMock('Doctrine\Bundle\DoctrineBundle\Registry', array('getManager'), array(), '', false);
    }

    protected function getSessionMock()
    {
        return $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('getFlashBag'), array(), '', false);
    }

    protected function getRouterMock()
    {
        return $this->getMock('Symfony\Component\Routing\Router', array('generate'), array(), '', false);
    }
}

よくテストされたコードを書いて、コミュニティが私を助けてくれることを願っています:)

乾杯

4

1 に答える 1