我模仿了你的逻辑,它运行良好。我用 Play 文档中的复制粘贴替换了您的一些代码,只是为了保持最小化。我在我现在正在处理的设置之上对其进行了测试,因此您会看到与默认 Play 设置不同的伪影。此设置或多或少与我最初链接的文章中描述的设置相同。我不知道如何比这更直接:
在控制器中:
import play.api.data._
import play.api.data.Forms._
case class UserData(name: String, age: Int)
val userFormConstraints2 = Form(
mapping(
"name" -> nonEmptyText,
"age" -> number(min = 0, max = 100)
)(UserData.apply)(UserData.unapply)
)
def test = Action {
implicit request => {
userFormConstraints2.bindFromRequest().fold(
formWithErrors => BadRequest("bad"),
userData => {
Ok(userData.name + userData.age)
}
)
}
}
测试:
class TempSpec extends Specification with MyHelpers {
"1" can {
"direct access to controller while posting" in new TestServer {
// `in new TestServer` spawns dependencies (`server`)
val controller = new controllers.Kalva(server)
// I instantiate the controller passing the dependency
val request = FakeRequest(POST, "bla")
.withFormUrlEncodedBody(
"name" -> "Richard",
"age" -> "1"
)
val result = controller.test()(request)
status(result) must equalTo(OK)
contentAsString(result) must contain("Richard");
val request_bad = FakeRequest(POST, "bla")
.withFormUrlEncodedBody(
"name" -> "",
"age" -> "-1"
)
val result_bad = controller.test()(request_bad)
status(result_bad) must equalTo(400)
contentAsString(result_bad) must contain("bad");
}
}
}
全局.scala:
object Global extends GlobalSettings {
private lazy val injector = Guice.createInjector(new TestModule)
override def getControllerInstance[A](controller: Class[A]) = {
injector.getInstance(controller)
}
}
测试模块:
import com.google.inject._
import com.tzavellas.sse.guice.ScalaModule
class TestModule extends ScalaModule {
def configure() {
@Provides
def getServer:Server = {
...
}
}
}
文件内routes
:
POST /bla @controllers.Kalva.test
// the `@` prefix is needed because of how we fetch controllers
原答案如下:
class TranslateSpec extends Specification {
"Translate" should {
// The normal Play! way
"accept a name, and return a proper greeting" in {
running(FakeApplication()) {
val translated = route(FakeRequest(GET, "/greet/Barney")).get
status(translated) must equalTo(OK)
contentType(translated) must beSome.which(_ == "text/html")
contentAsString(translated) must contain ("Barney")
}
}
// Providing a fake Global, to explitly mock out the injector
object FakeTranslatorGlobal extends play.api.GlobalSettings {
override def getControllerInstance[A](clazz: Class[A]) = {
new Translate(new FakeTranslator).asInstanceOf[A]
}
}
"accept a name, and return a proper greeting (explicitly mocking module)" in {
running(FakeApplication(withGlobal = Some(FakeTranslatorGlobal))) {
val home = route(FakeRequest(GET, "/greet/Barney")).get
contentAsString(home) must contain ("Hello Barney")
}
}
// Calling the controller directly, without creating a new FakeApplication
// (This is the fastest)
"accept a name, and return a proper greeting (controller directly, no FakeApplication!)" in {
val controller = new Translate(new FakeTranslator)
val result = controller.greet(name = "Barney")(FakeRequest())
contentAsString(result) must contain ("Hello Barney")
}
}
}
上面的代码是非常自我描述的,它显示了默认的测试工作流程以及如何使用依赖注入来改进它。这是这篇文章的引文。
这段特别摘录来自“为什么我应该在 Play 中使用 DI?” 部分。这篇文章是关于使用 Play2 设置 Google Guice 以及它带来的可能性。这是一本实用的读物。
正如您在上面看到的,“正常的 Play! 方式”很好,但是通过采用 DI,您可以在测试(当然还有一般的开发)中摆脱更多。
如文章中所述,将 Guice 与 Play 一起使用需要对 Play 的默认设置进行细微更改,这是非常值得的。我已经这样做了很长时间了,并且没有回头。