【问题标题】:How can I execute this controller action code in an integration test?如何在集成测试中执行此控制器操作代码?
【发布时间】:2018-11-10 04:06:59
【问题描述】:

我正在使用 Scala Play 框架编写集成测试。

我在控制器中有一个看起来像这样的函数:

def myEndpoint: AnyAction = myActionProvider.securedEndpoint("myEndpoint") { implicit request =>
    // Business logic
    Ok("")
}

myActionProvider.securedEndpoint 使用andThen() 将一些操作构建器链接在一起并返回一个ActionBuilder

在我的集成测试中,我有以下内容:

val fakeRequest: FakeRequest = buildFakeRequest()
myController.myEndpoint.apply(fakeRequest)

虚假请求包含生成的安全令牌和我们的应用所需的其他标头。

我能够闯入myActionProvider.securedEndpoint 并跟踪执行。但是,我无法破解任何 invokeBlock 方法,也无法破解控制器的业务逻辑。日志显示这些路径从未被执行。

如果我将myController.myEndpoint.apply(fakeRequest) 的结果保存到一个变量中,它的类型是Accumulator[ByteString, Result]。看起来这包含链接的 Action 构建器和业务逻辑代码块,但 Play 从不执行它。

代码不会抛出异常,也不会向控制台输出任何内容。

我想知道这是否是我的测试语法错误。我也尝试了以下方法,但无济于事:

  • myController.myEndpoint { fakeRequest }
  • myController.myEndpoint()(fakeRequest)

是的,代码以“常规”方式运行,例如非测试环境:)

【问题讨论】:

    标签: scala playframework integration-testing


    【解决方案1】:

    我创建了一个关于如何测试控制器here 的工作示例。它基于 Play 2.6.15 with Guice 并使用 scalatestplus-play 库。

    libraryDependencies ++= Seq(
      "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % "test"
    )
    

    这是一个有两个动作的控制器:

    import javax.inject.Inject
    import play.api.mvc._
    
    class ApplicationController @Inject()(controllerComponents: ControllerComponents)
      extends AbstractController(controllerComponents) {
    
      def foo(): Action[AnyContent] = Action { request =>
        Ok(s"I am listening at ${request.uri}")
      }
    
      def bar: Action[String] = Action(parse.tolerantText) { request =>
        Ok(s"Received body of size: ${request.body.length}")
      }
    }
    

    带有显式正文解析器的操作确实会返回一个Accumulator 对象。有趣的是,使用默认正文解析器的操作返回 Future

    不过,在这两种情况下,play-test 库都提供了帮助器,用于从两种类型的结果中提取结果正文、状态和其他内容。

    import akka.stream.Materializer
    import akka.util.ByteString
    import org.scalatestplus.play._
    import play.api.http.Status
    import play.api.inject.guice.GuiceApplicationBuilder
    import play.api.libs.streams.Accumulator
    import play.api.mvc._
    import play.api.test.Helpers._
    import play.api.test._
    
    import scala.concurrent.Future
    
    class ApplicationControllerTest extends PlaySpec {
    
      "ApplicationController" should {
    
        val application = new GuiceApplicationBuilder().build()
        val controller = application.injector.instanceOf[ApplicationController]
    
        "return correct response for foo" in {
          val result: Future[Result] = controller.foo().apply(FakeRequest("GET", "/testUriFoo"))
          contentAsString(result) mustBe "I am listening at /testUriFoo"
          status(result) mustBe Status.OK
        }
    
        "return correct response for bar" in {
          implicit val mat: Materializer = application.materializer
          val fakeRequest = FakeRequest("POST", "/testUriBar").withTextBody("123456789")
          val result: Accumulator[ByteString, Result] = controller.bar().apply(fakeRequest)
          contentAsString(result) mustBe "Received body of size: 9"
          status(result) mustBe Status.OK
        }
    
      }
    
    }
    

    使用的资源:

    【讨论】:

    • 谢谢。从您提供的资源中,我还了解到调用 controller.bar()(fakeRequest) 会返回 Future[Result],从而不再需要物化器。
    猜你喜欢
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多