コントローラがプレイフレームワークのビューに渡す引数に対してテストを実行する方法

StackOverflow https://stackoverflow.com//questions/20005032

  •  20-12-2019
  •  | 
  •  

質問

プレイアプリケーションでは、すべてのコントローラ機能がデータベースからデータを取得し(他の方法)、これらの値を結果

に渡します。
def index = Action { implicit request =>
    val newsItems: List[String] = fetchNewsFromDB()
    Ok(views.html.home.index(newsItems))
  }

def fetchNewsFromDB() = List("Headline1", "Headline2")
.

指定を使用してテストを使用しています(ドキュメントに基づく http://www.playframework.com / documentation / 2.2.x / scalatest

次のようなコントローラによるこの文書によると。次のテストでは、インデックスページに見出しが含まれていることを確認したいです。クラス "Headline"

のDIVが存在するかどうかを確認します。
"Example Page#index" should {
    "should contain a headline" in {
      val controller = new TestController()
      val result: Future[SimpleResult] = controller.index().apply(FakeRequest())
      val bodyText: String = contentAsString(result)
      bodyText.toLowerCase must contain("<div class=\"headline\"")
    }
  }
.

しかしながら、コントローラがビューに渡すリストのNewsItemがNenemptyであるかどうかを確認します。

これを行う最善の方法は何ですか? これは、コントローラの変更がほとんど必要な一般的な方法では可能ですか?

役に立ちましたか?

解決

私もテンプレートへの道にパラメータを傍受することができなかったことが失望されました - そして実際にはテンプレートをテストでにすることをテストでのレンダリングすることを非常に困難にすることができます。あなたのページに「状態」がたくさんあります(たとえば、ユーザーオブジェクト、ナビゲーションヘルパーなどを提供する意味)

私が終わったことは、私のコントローラーのテスト能力のために余分な「縫い目」に入っていました。マイテストでは、I Expend テスト中のコントローラをextend を拡張し、HTMLレンダリング関数をモック付きのものに置き換えます。その後、パラメータを確認できます。

あなたの「ニュース」行動に基づく簡単な例です。まず、Controllerはobjectではなく、それを拡張できます。

object Application extends ApplicationController

trait ApplicationController extends Controller {

  def newsAction = Action {
    Ok(renderNews("this is the news"))
  }

  def renderNews(s:List[String]):Html = html.sandbox(s)
}
.

renderNewsメソッドには、All重要な「テストSeam」が付与されています。私も実際にコントローラメソッドの読みやすさも実際に改善されていると思います。 - )

今、単体テスト:

class ApplicationSpec extends Specification with Mockito {

  val mockedNewsRenderer = mock[List[String] => Html]

  val controller = new ApplicationController {
    override def renderNews(s:List[String]) = mockedNewsRenderer(s)
  }

  "Application News Controller" should {

    "Pass a non-empty list of news items to the template" in {
      val result = controller.newsAction(FakeRequest())

      status(result) must beEqualTo(200)

      val captor = ArgumentCaptor.forClass(classOf[List[String]])

      there was one(mockedNewsRenderer).apply(captor.capture())
      val theArgument = captor.getValue
      theArgument.isEmpty must beFalse
    }
  }
}
.

renderNews関数のスタンドインを作成し、それを置換できるようにコントローラを拡張してから、(もちろん他のものは他には変更されず、通常どおりに変更してください)。まだ標準のPlay Resultを入手するので、ステータスコードなどを確認できますが、 mockito specs2 に組み込まれている機能性を検証します。http://docs.mockito.googlecode.com/hg/org/mockito /argumentcaptor.html "rel=" nofollow "> MockitoのArgumentCaptor機能テンプレートが実際に呼び出されたこと、およびそれが空でない文字列のリストを指定したことを主張します。

このアプローチは私にとってうまくいっています - それは急速に実行されやすい単体テストでコントローラの本当に良いコードカバレッジを得ることを可能にします。

他のヒント

You have a very good question and a very valid point on testing controllers, but I'm afraid it can't be done easily. The problem is that the views compile to Scala functions meaning when you call views.html.home.index(newsItems) it will return an object of Html, which already has the Html put together and compiled. If you would like to test what get's passed in you need to intercept it before the view is called.

To solve this you would have to rewrite your controllers, by moving all your business logic out of the controller and only have the necessary request handling code there. That would almost be easier to test.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top