如何在集成测试中执行此控制器操作代码?
How can I execute this controller action code in an integration test?
我正在使用 Scala Play 框架编写集成测试。
我在控制器中有一个如下所示的函数:
def myEndpoint: AnyAction = myActionProvider.securedEndpoint("myEndpoint") { implicit request =>
// Business logic
Ok("")
}
myActionProvider.securedEndpoint
使用 andThen()
和 returns 和 ActionBuilder
.
将一些动作构建器链接在一起
在我的集成测试中,我有以下内容:
val fakeRequest: FakeRequest = buildFakeRequest()
myController.myEndpoint.apply(fakeRequest)
虚假请求包含生成的安全令牌和我们应用所需的其他 headers。
我能够闯入 myActionProvider.securedEndpoint
并跟随处决。但是,我无法进入任何 invokeBlock
方法,也无法进入控制器的业务逻辑。日志记录显示这些路径从未执行过。
如果我将myController.myEndpoint.apply(fakeRequest)
的结果保存到一个变量中,它的类型是Accumulator[ByteString, Result]
。看起来这包含链接的 Action 构建器和业务逻辑代码块,但 Play 从未执行它。
代码没有抛出任何异常,也没有任何内容输出到控制台。
我在想是不是我的测试语法有误。我也尝试了以下方法,但无济于事:
myController.myEndpoint { fakeRequest }
myController.myEndpoint()(fakeRequest)
是的,代码在 "regular" 例如non-testing环境:)
我创建了一个关于如何测试控制器的工作示例 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}")
}
}
具有显式正文解析器的操作确实 return 一个 Accumulator
对象。有趣的是,使用默认正文解析器 return 的操作是 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
}
}
}
使用的资源:
我正在使用 Scala Play 框架编写集成测试。
我在控制器中有一个如下所示的函数:
def myEndpoint: AnyAction = myActionProvider.securedEndpoint("myEndpoint") { implicit request =>
// Business logic
Ok("")
}
myActionProvider.securedEndpoint
使用 andThen()
和 returns 和 ActionBuilder
.
在我的集成测试中,我有以下内容:
val fakeRequest: FakeRequest = buildFakeRequest()
myController.myEndpoint.apply(fakeRequest)
虚假请求包含生成的安全令牌和我们应用所需的其他 headers。
我能够闯入 myActionProvider.securedEndpoint
并跟随处决。但是,我无法进入任何 invokeBlock
方法,也无法进入控制器的业务逻辑。日志记录显示这些路径从未执行过。
如果我将myController.myEndpoint.apply(fakeRequest)
的结果保存到一个变量中,它的类型是Accumulator[ByteString, Result]
。看起来这包含链接的 Action 构建器和业务逻辑代码块,但 Play 从未执行它。
代码没有抛出任何异常,也没有任何内容输出到控制台。
我在想是不是我的测试语法有误。我也尝试了以下方法,但无济于事:
myController.myEndpoint { fakeRequest }
myController.myEndpoint()(fakeRequest)
是的,代码在 "regular" 例如non-testing环境:)
我创建了一个关于如何测试控制器的工作示例 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}")
}
}
具有显式正文解析器的操作确实 return 一个 Accumulator
对象。有趣的是,使用默认正文解析器 return 的操作是 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
}
}
}
使用的资源: