web-dev-qa-db-ja.com

Drupal単体テストにサービスを挿入しますか?

まだ存在しないサービスの単体テストを事前に作成しています。それがResponseFormatterと呼ばれているとしましょう。

このサービスで実行することを期待するための単体テストを追加したいと思います。 UnitTestCaseに挿入したり、参照したりするにはどうすればよいですか?

例、私は次のようなことをやろうとしています:

class FormatterTest extends UnitTestCase {

  /**
   * @dataProvider responses
   */
  public function testThisWorks($response, $expected) {
    // the following line I want to call a service, 
    // ex. like $this->responseFormatter->format($string);
    $clean = html_entity_decode(strip_tags($response));
    $this->assertEquals($expected, $clean);
  }

  public function responses() {
    return [
      ['not-set', 'not-set'],
      ['<strong>foo</strong>', 'foo'],
      ['&amp; #93 bar', '& #93 bar'],
    ];
  }
}
5
Kevin

新しいサービスが十分に独立している(独自の依存関係がまったくない、または多くない)場合は、setUp()を作成します。そして、依存関係がある場合は、 mocks (doubleとも呼ばれます)を設定します。

コアのthisの例は TimeTest::setUp() です:

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

  $this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
  $this->time = new Time($this->requestStack);
}
_

モック化されたリクエストスタックが作成され、セットアップはテスト対象のサービスクラス(この場合、 Time() )を直接インスタンス化し、モック化された依存関係をコンストラクターに渡します。

次に、テストメソッドのアサーションはかなり単純です

_public function testGetRequestTime() {
  $expected = 12345678;

  $request = Request::createFromGlobals();
  $request->server->set('REQUEST_TIME', $expected);

  // Mocks a the request stack getting the current request.
  $this->requestStack->expects($this->any())
    ->method('getCurrentRequest')
    ->willReturn($request);

  $this->assertEquals($expected, $this->time->getRequestTime());
}
_

モックはサービスの依存関係が何をするかをシミュレートし、サービスメソッドが直接呼び出されます。

サービスに多くの依存関係がある場合、またはサービスのモックが難しい場合は、KernelTestまたはTestCaseではなくUnitTestを実行する必要があります。ただし、それはサービスが複雑すぎて分割する必要があることを示している可能性があります(ユニットテストではなくカーネルテストされているコアサービスについても問題が発生しています)。

8
mpdonadio