在我们的播放应用程序中,每个控制器函数都从数据库(或某种其他方式)获取数据,并将这些值传递给结果

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

根据控制器的文件如下。在下一个测试中,我想确保索引页面包含标题。我通过检查是否存在类别“标题”

"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\"")
    }
  }
. 但是,我宁愿检查控制器传递到视图的列表新闻是不是空的。

是什么最好的方法? 是否有可能以一种通用方式,以便需要对控制器进行很少的修改?

有帮助吗?

解决方案

我也沮丧,我无法在他们的路上拦截参数 - 实际上它可能变得非常困难,甚至可以在测试中得到模板来渲染在页面中有很多“状态”(例如,提供用户对象,导航效果等的含义)。

我最终做了在我的控制器中的额外的“缝”中放入额外的“缝”;在我的测试中,I 扩展了“被测的控制器”,用嘲弄的控制器替换HTML渲染功能,然后我可以使用它来验证参数。

这是一个简单的例子,基于你的“新闻”动作;首先,控制器,它不再是生成的,所以我们可以扩展它:

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)
}
.

object方法为我们提供全部重要的“测试缝”。我认为它还实际上还提高了控制器方法的可读性,这很好: - )

现在,单位测试:

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函数,扩展控制器,以便我们可以替换它(请注意,当然,我们不会改变其他任何东西),然后将动作正常调用。请注意,我们仍然获得标准播放生成的renderNews,因此我们仍然可以检查状态代码等,但是,我们可以使用 mockito验证功能,它内置于specs2 中,与 mockito的Result facility 要断言我们的模板确实被称为,并且它提供了一个非空字符串列表。

这种方法对我来说已经很好地工作了 - 它可以通过快速运行和易于写的单元测试来获得控制器的真正良好的代码覆盖。

其他提示

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