scala - 如何对 Controller 传递给 Play Framework 中的 View 的参数执行测试

标签 scala playframework-2.0

在我们的 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/

相关文章:

scala - 玩框架 2.4、Guice 和 securesocial

scala - 避免 Java MPI 绑定(bind)中的命名空间冲突

scala - 为方法 Apply 提供太多参数

scala - Play Framework scala如何创建临时变量

java - Play2 "include"指令覆盖配置并替换

json - 如何在Play中替换JSON值

scala - 给定任何类类型的实例,如何找出它继承或实现的父类和/或特征?

java - 编写自定义 Kafka 序列化器

javascript - Play Framework 2 : JavaScript gets duplicated as a result of minification (google closure compiler)

java - 自动将通配符导入重构为 IntelliJ 中的显式导入(适用于 Scala/Java)