在我们的 play 应用程序中,每个 Controller 函数都从数据库(或其他方式)获取数据并将这些值传递给结果
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)
根据 Controller 的文档如下。在下一个测试中,我想确保索引页包含标题。我通过检查是否存在类为“标题”的 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\"")
}
}
但是我宁愿检查 Controller 传递给 View 的列表 newsItems 是否是非空的。
最好的方法是什么? 是否可以通过对 Controller 进行少量修改的通用方式实现这一点?
最佳答案
我也很沮丧,因为我无法在传递给模板的过程中拦截参数 - 事实上,如果您在您的页面中有很多“状态”(例如,提供用户对象、导航助手等的隐式)。
我最终做的是在我的 Controller 中添加一个额外的“接缝”以实现可测试性;在我的测试中,我扩展被测 Controller ,将 HTML 呈现函数替换为模拟函数,然后我可以使用它来验证参数。
这是一个基于您的“新闻”操作的简单示例;首先是 Controller ,它不再是一个对象
,所以我们可以扩展它:
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
方法为我们提供了最重要的“测试接缝”。我认为它实际上也提高了 Controller 方法的可读性,这很好:-)
现在,单元测试:
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
函数,扩展 Controller 以便我们可以替换它(注意我们当然没有改变它的任何其他内容),并且然后正常调用操作。请注意,我们仍然得到一个标准的 Play Result
,因此我们仍然可以检查状态代码等,但是我们可以使用 Mockito verify functionality that's built into Specs2 , 连同 Mockito's ArgumentCaptor
facility断言我们的模板确实被调用了,并且它提供了一个非空的字符串列表。
这种方法对我来说效果很好 - 它可以通过快速运行且易于编写的单元测试获得非常好的 Controller 代码覆盖率。
关于scala - 如何对 Controller 传递给 Play Framework 中的 View 的参数执行测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20005032/