2013-07-09 3 views
7

2つのパラメータを受け取るアクションを持つコントローラがあります。プレイフレームワークのコントローラをユニットテストする方法2 scala

それはテンプレート

結果がOKに渡され、返されるに2つのサービスは、各パラメータを使用して1、これらの文字列のそれぞれは、引数として渡されるサービスの両方

リターン文字列を呼び出します。

は私が保証しますシンプルなユニットテスト書きたい: 1 - 正しいサービスが 2正しいパラメータで呼び出された - サービスからの戻り値は、テンプレートの正しい属性に渡され

何それを行う最善の方法は何ですか?

+0

(コントローラはIMOちょうど配管のためのものである)他のいくつかのコンポーネントによって行われるべきであるという現実の世界では、このケースではあります.0? – 4lex1v

+0

具体的には、specs2.0を使用してサービスの呼び出しとテンプレートの呼び出しをインターセプトするテストを作成するにはどうすればよいですか?私がアプリケーションを全体としてテストする例(統合) –

答えて

2

Spec2を使ってMockitoを使って、私はメソッド呼び出しを検証するサービスを模擬します。

コントローラはSpringによってインスタンス化されます。それで私はそれをobjectの代わりにclassとして扱うことができます。 =>それはcontrollerをテスト可能にするために不可欠です。ここでは例:

@Controller 
class MyController @Autowired()(val myServices: MyServices) extends Controller 

コントローラの春を有効にするには、プレイとして、Globalオブジェクトを定義する必要があります!ドキュメントの説明:

object Global extends GlobalSettings { 

    val context = new ClassPathXmlApplicationContext("application-context.xml") 

    override def getControllerInstance[A](controllerClass: Class[A]): A = { 
    context.getBean(controllerClass) 
    } 
} 

私のユニットテストにはSpringは必要ありません。私はコンストラクタ(モック)をコンストラクタに渡すだけです。

しかし、レンダリングされたテンプレートに関しては、結果のタイプ(OK、BadRequest、Redirectionなど)のみをテストします。 実際、私のテストでは、レンダリングされたテンプレート全体を詳細に(パラメータなどを送信して)スキャンし、単体テストしか行わないのは簡単ではないことに気付きました。

このように、適切な引数を指定して正しいテンプレートが呼び出されることを確認するために、私は受け入れテストをSeleniumで実行するか、機能テストを実行して期待される結果全体をスキャンします。

2 - サービスからの戻り値は、テンプレート

の正しい 属性に渡され、それはthat..Howをチェックするために非常に簡単ですか!コンパイラを信頼することによって!たとえば、単純なプリミティブではなく、テンプレートにカスタムタイプを渡すことをお勧めします。 phone: Stringは、phone: Phoneになります。 (単純な値オブジェクト)。 したがって、予想外の順序で属性をテンプレートに渡すことはありません(単体テストまたは実運用コードで)。コンパイラは実際に警告します。

specs2を使用した単体テスト(簡略化)の例を次に示します。 (ラッパーの使用に注意してください:WithFreshMocks) このcase classは、テスト後にすべての変数(この場合はモック)をリフレッシュすることができます。 したがって、モックをリセットするには良い方法です。

class MyControllerSpec extends Specification with Mockito { 

     def is = 
     "listAllCars should retrieve all cars" ! WithFreshMocks().listAllCarsShouldRetrieveAllCars 

     case class WithFreshMocks() { 

     val myServicesMock = mock[MyServices] 
     val myController = new MyController(myServicesMock) 

     def listAllCarsShouldRetrieveAllCars = { 
      val FakeGetRequest = FakeRequest() //fakeRequest needed by controller 
      mockListAllCarsAsReturningSomeCars() 
      val result = myController.listAllCars(FakeGetRequest).asInstanceOf[PlainResult] //passing fakeRequest to simulate a true request 
      assertOkResult(result). 
      and(there was one(myServicesMock).listAllCars()) //verify that there is one and only one call of listAllCars. If listAllCars would take any parameters that you expected to be called, you could have precise them. 
     } 

     private def mockListAllCarsAsReturningSomeCars() { 
      myServicesMock.listAllCars() returns List[Cars](Car("ferrari"), Car("porsche")) 
     } 

     private def assertOkResult(result: PlainResult) = result.header.status must_== 200 

     } 
+1

私はテンプレートを模擬することができる解決策を考え出しましたが、タイプシステムを使用してテストエラーではなくコンパイラエラーを得ることを認めています不正な引数を使用する –

2

だから、私はケーキのパターンとmockitoベースのソリューションを思い付いた:

サービス与えられた:

trait Service { 
    def indexMessage : String 
} 

trait ServiceImpl { 
    def indexMessage = { 
    "Hello world" 
    } 
} 

そして、コントローラは、次のようになります。

object Application extends ApplicationController 
        with ServiceImpl { 
    def template = views.html.index.apply 
} 

trait ApplicationController extends Controller 
          with Service { 
    def template: (String) => play.api.templates.Html 

    def index = Action { 
    Ok(template("controller got:" + indexMessage)) 
    } 
} 

そして、テストは次のようになります。

class ApplicationControllerSpec extends Specification with Mockito { 
    "cake ApplicationController" should { 
     "return OK with the results of the service invocation" in { 
     val expectedMessage = "Test Message" 
     val m = mock[(String) => play.api.templates.Html] 

     object ApplicationControllerSpec extends ApplicationController { 
      def indexMessage = expectedMessage 
      def template = m 
     } 

     val response = ApplicationControllerSpec.index(FakeRequest()) 

     status(response) must equalTo(OK) 
     there was one(m).apply(Matchers.eq("controller got:" + expectedMessage)) 
     } 
    } 
} 

私はMockitoを動作させるのに苦労しました。
文字列を使用しないよう、

最終的に私は上記の答えは優れていると思います(私はJavaでそれを使用して非常に快適だ)それは余分な依存関係を必要とし、私はScalaでの照合プログラムを使用する方法をワークアウトのトラブルの多くを持っていました他のプリミティブ型をタスク固有の型でラップすると、コンパイラの警告が表示されます。

また、私は一般的に、コントローラに "controller got:"接頭辞のようなことをしないでください。

私はそれが通過したことを確認することができますので、それはなぜScalaCheck/ScalaTest/Specs2を使用しない

+0

演劇で動かない2.3.8 – zengr

関連する問題