【问题标题】:How to test Zentasks sample app from Play 2.0如何从 Play 2.0 测试 Zentasks 示例应用程序
【发布时间】:2012-04-01 13:38:01
【问题描述】:

我玩的是 Play 2.0,Scala 版本。目前,我分析Zentasks sample app

这个应用程序的一部分是身份验证机制,主要包含在Secured trait 中。我想知道如何测试安全操作,例如。 index 来自Projects controller

对于不安全的操作,我可能会做类似的事情

val result = controllers.Projects.index(FakeRequest())

运行一个动作并得到它的结果。

遇到安全动作怎么办?

免责声明:我对 Scala 和 Play 都是全新的,所以所有提示都非常有价值。谢谢!

【问题讨论】:

    标签: scala testing playframework-2.0


    【解决方案1】:

    Playframewrk v2.1 中有一个fix for the integrated approach to this 我有一个backport of the fix on the 2.0.x branch

    在它被合并和发布之前,这是我所做的(它适用于 Play 2.0.3+):

    我像这样在 libs 包中定义了自己的 Helpers 对象。

    package libs
    
    import play.api.mvc._
    
    import play.api.libs.iteratee._
    import play.api.libs.concurrent._
    import play.api.test._
    
    object Helpers {
    
      def routeAndCall[T](request: FakeRequest[T]): Option[Result] = {
        routeAndCall(this.getClass.getClassLoader.loadClass("Routes").asInstanceOf[Class[play.core.Router.Routes]], request)
      }
      /**
       * Use the Router to determine the Action to call for this request and executes it.
       */
      def routeAndCall[T, ROUTER <: play.core.Router.Routes](router: Class[ROUTER], request: FakeRequest[T]): Option[play.api.mvc.Result] = {
        val routes = router.getClassLoader.loadClass(router.getName + "$").getDeclaredField("MODULE$").get(null).asInstanceOf[play.core.Router.Routes]
        routes.routes.lift(request).map {
          case a: Action[_] =>
            val action = a.asInstanceOf[Action[T]]
            val parsedBody: Option[Either[play.api.mvc.Result, T]] = action.parser(request).fold(
              (a, in) => Promise.pure(Some(a)),
              k => Promise.pure(None),
              (msg, in) => Promise.pure(None)
            ).await.get
    
            parsedBody.map{resultOrT =>
              resultOrT.right.toOption.map{innerBody =>
                action(FakeRequest(request.method, request.uri, request.headers, innerBody))
              }.getOrElse(resultOrT.left.get)
            }.getOrElse(action(request))
        }
      }
    
    }
    

    然后在我的测试中,我导入了我的 Helpers 和整个 play Helpers 上下文,除了 routeAndCall :

    import libs.Helpers._
    import play.api.test.Helpers.{routeAndCall => _,_}
    

    然后我使用 Around 来设置我的应用程序(我需要提供一个 application.secret,因为我将经过身份验证的用户名存储在基于签名 cookie 的会话中)

    def appWithSecret():Map[String,String]={
        Map(("application.secret","the answer is 42 !"))
      }
    
    
      object emptyApp extends Around {
        def around[T <% Result](t: => T) = {
          running(FakeApplication(additionalConfiguration = inMemoryMongoDatabase("emptyApp")++appWithSecret())) {
            User(new ObjectId, "Jane Doe", "foobar@example.com", "id1").save()
            t // execute t inside a http session
          }
        }
      }
    

    这允许我编写以下测试:

    "respond to the index Action" in emptyApp {
          val request: FakeRequest[AnyContent] = FakeRequest(GET, "/expenses").withSession(("email", "foobar@example.com"))
          val Some(result) = routeAndCall(request)
    
          status(result) must equalTo(OK)
          contentType(result) must beSome("application/json")
          charset(result) must beSome("utf-8")
          contentAsString(result) must contain("Hello Bob")
        }
    

    即使它不是单元测试,它也允许您使用安全代码。

    【讨论】:

      【解决方案2】:

      好吧,我也不是很好的专家,但这里有一个想法。

      创建一个trait InSecure trait extends Secured,它会覆盖受保护的操作并始终允许访问。 然后你可以在你的测试中创建一个object InSecureProjects extends Projects with InSecture,这应该只覆盖安全检查,让你在没有任何安全性的情况下测试操作。

      现在,不是在 Projects 上运行测试,而是在 InSecureProjects 上运行它们。您可以对其他安全控制器执行完全相同的操作。

      我还没有测试过,所以让我知道它是否有效;)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-03
        • 1970-01-01
        • 1970-01-01
        • 2014-07-09
        • 2015-04-19
        • 2012-04-03
        相关资源
        最近更新 更多