scala – Play Framework,Specs2 – 直接从单元测试调用控制器方
我的控制器中有一个方法,我想直接打电话.它接受一个POSTed表单,验证它,然后返回一些东西.我想直接测试它 – 即不通过路线助手.
这是我的表单代码(FormFields只是一个案例类) val searchForm = Form( mapping( "foo" -> nonEmptyText,"filter" -> optional(text).verifying("Filter text must be 'published' or 'unpublished'",x => x.isEmpty || x.get == "published" || x.get == "unpublished") )(FormFields.apply)(FormFields.unapply) ) 这是我的控制器电话. def doThings() = IsAuthenticated { username => implicit request => { searchForm.bindFromRequest().fold( formWithErrors => BadRequest(s"Incorrect data: ${formWithErrors.errors.map(x => s"${x.key} ${x.message}").mkString}."),form => { OK("Test text here") } ) } } 如果我通过我的路由文件调用此方法,如下所示 – 这可以按预期工作.表格被发布,验证,按预期返回OK(“测试…”). 即.以下工作(使用Specs2) val request = FakeRequest(POST,"notarealurl") .withFormUrlEncodedBody( "filter" -> "published","foo" -> "Test" ).withSession("email" -> "testuser") val Some(result) = route(request) status(result) must equalTo(OK) 但是,无论我试图直接调用该方法失败 – 失败发生在表单验证步骤.它告诉我,当我运行单元测试时,“foo”缺少一个值.这就是我试图这样做的方式. val request = FakeRequest() .withFormUrlEncodedBody( "filter" -> "published","foo" -> "Test" ).withSession("email" -> "testuser") //val Some(result) = route(request) val result = Search.searchProducts()(request) println(contentAsString(result)) status(result) must equalTo(OK) 打印的文字是“搜索不正确:foo error.required”.我想我没有正确地打电话,但我不知道我哪里出错了. 注意:此处的代码代表我的问题,但已被删除以说明问题. 解决方法
我模仿你的逻辑,它运行良好.我用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"); } } } Global.scala: object Global extends GlobalSettings { private lazy val injector = Guice.createInjector(new TestModule) override def getControllerInstance[A](controller: Class[A]) = { injector.getInstance(controller) } } TestModule: import com.google.inject._ import com.tzavellas.sse.guice.ScalaModule class TestModule extends ScalaModule { def configure() { @Provides def getServer:Server = { ... } } } 在路线文件中: 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") } } } 上面的代码非常自我描述,它显示了默认的测试工作流以及如何使用依赖注入来改进它.这是this article的报价. 这个特别的摘录来自“我为什么要在游戏中使用DI?”部分.这篇文章是关于使用Play2设置Google Guice以及它打开的可能性.这是一个实用的阅读. 正如你在上面所看到的那样,“正常的Play!方式”很好,但是通过接受DI,你可以在测试中获得更多(当然还有开发). 正如文章中所描述的,使用Guice with Play涉及对Play的默认设置进行微小更改,这非常值得.我已经这么做了很久了,并没有回头. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |