简体   繁体   English

使用扩展控制器播放 2.4 macwire 示例似乎无法模拟

[英]Play 2.4 macwire example with extended controllers doesn't seem like it can be mocked

I took the existing macwire example and extended the controller like so CoffeeController.scala我采用现有的 macwire 示例并像这样扩展控制器 CoffeeController.scala

package com.softwaremill.play24.controllers

import com.softwaremill.play24.dao.CoffeeDao
import play.api.i18n.Lang
import play.api.libs.json.Json
import play.api.mvc._

import scala.concurrent.{Future}
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.mvc.Results._

class CoffeeController(
  coffeeDao: CoffeeDao
)(implicit ec: SomeContextBuilder) extends AnotherController {

  def fetchAll() = DecoratedAction() { request =>
    coffeeDao.all.map { coffees =>
      Ok(Json.toJson(coffees))
    }
  }

  def priced(price: Double) = ResolvedDecoratedAction() { request =>
    coffeeDao.byPriceWithSuppliers(price).map { result =>
      Ok(Json.toJson(result.toMap))
    }
  }
}

trait ContextBuilder[U <: TraitLike] {
  def build(request: Request[AnyContent]): Future[Either[Result, RequestWithContext[U]]]
  def buildAuthenticated(request: Request[AnyContent]): Future[Either[Result, RequestWithResolvedContext[U]]]
}

trait TraitLike {
  def id: String
}

trait WithSessionId {
  self: RequestHeader =>
  lazy val sessionId = self.session.get("auth").getOrElse(java.util.UUID.randomUUID().toString)
}

case class RequestWithContext[U <: TraitLike](request: Request[AnyContent], lang: Lang, anything: Option[U]) extends WrappedRequest(request) with WithSessionId
case class RequestWithResolvedContext[U <: TraitLike](request: Request[AnyContent], lang: Lang, anything: U, rememberMe: Boolean = false) extends WrappedRequest(request) with WithSessionId
case class Trait(val id: String) extends TraitLike

class AnotherController[U <: TraitLike](implicit ctxBuilder: ContextBuilder[U]) extends Controller  {
  def DecoratedAction(bodyParser: BodyParser[AnyContent] = parse.anyContent)(f: RequestWithContext[U] => Future[Result]) = Action.async {
    implicit request =>
      ctxBuilder.build(request) flatMap {
        case Left(r) =>
          Future.successful(r)
        case Right(requestContext) =>
          f(requestContext).map(_.addingToSession( ("auth" , requestContext.sessionId) ))
      }
  }

  def ResolvedDecoratedAction(bodyParser: BodyParser[AnyContent] = parse.anyContent)(f: RequestWithResolvedContext[U] => Future[Result]) = Action.async {
    implicit request =>
      ctxBuilder.buildAuthenticated(request) flatMap {
        case Left(r) =>
          Future.successful(r)
        case Right(requestContext) =>
          f(requestContext).map(_.addingToSession( ("auth", requestContext.sessionId) ))
      }
  }
}

class SomeContextBuilder extends ContextBuilder[TraitLike] {
  override def build(request: Request[AnyContent]): Future[Either[Result, RequestWithContext[TraitLike]]] = Future.successful(Right(RequestWithContext(request, Lang("en-us"),None)))

  override def buildAuthenticated(request: Request[AnyContent]): Future[Either[Result, RequestWithResolvedContext[TraitLike]]] = Future.successful(Right(RequestWithResolvedContext(request, Lang("en-us"),Trait("id"),false)))
}

ControllerModule.scala控制器模块.scala

package com.softwaremill.play24.modules

import com.softwaremill.macwire._
import com.softwaremill.play24.controllers.{SomeContextBuilder, SupplierController, CoffeeController}
import com.softwaremill.play24.dao.{CoffeeDao, SupplierDao}
import play.api.libs.ws.WSClient

import scala.concurrent.ExecutionContext

trait ControllerModule {

  // Dependencies
  implicit def ec: ExecutionContext
  implicit val ctxBuilder = wire[SomeContextBuilder]
  def wsClient: WSClient
  def supplierDao: SupplierDao
  def coffeeDao: CoffeeDao

  // Controllers
  lazy val supplierController = wire[SupplierController]
  lazy val coffeeController = wire[CoffeeController]
}

However when I run the tests I'm getting a stacktrace:但是,当我运行测试时,我得到了一个堆栈跟踪:

[error]   ! return priced by coffee, supplier
  [error]    No configuration setting found for key 'play.crypto.secret' (SimpleConfig.java:152)
[error] com.typesafe.config.impl.SimpleConfig.findKeyOrNull(SimpleConfig.java:152)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:170)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:176)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:176)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:193)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:198)
[error] com.typesafe.config.impl.SimpleConfig.getIsNull(SimpleConfig.java:208)
[error] play.api.PlayConfig.getOptional(Configuration.scala:951)
[error] play.api.PlayConfig.getOptionalDeprecated(Configuration.scala:996)
[error] play.api.libs.CryptoConfigParser.get$lzycompute(Crypto.scala:232)
[error] play.api.libs.CryptoConfigParser.get(Crypto.scala:203)
[error] play.api.libs.Crypto$$anonfun$crypto$1.apply(Crypto.scala:42)
[error] play.api.libs.Crypto$$anonfun$crypto$1.apply(Crypto.scala:40)
[error] play.api.libs.Crypto$.crypto(Crypto.scala:43)
[error] play.api.libs.Crypto$.sign(Crypto.scala:67)
[error] play.api.mvc.CookieBaker$class.encode(Http.scala:502)
[error] play.api.mvc.Session$.encode(Http.scala:651)
[error] play.api.mvc.CookieBaker$class.encodeAsCookie(Http.scala:554)
[error] play.api.mvc.Session$.encodeAsCookie(Http.scala:651)
[error] play.api.mvc.Result.withSession(Results.scala:170)
[error] play.api.mvc.Result.addingToSession(Results.scala:262)
[error] com.softwaremill.play24.controllers.AnotherController$$anonfun$ResolvedDecoratedAction$1$$anonfun$apply$5$$anonfun$apply$6.apply(CoffeeController.scala:64)
[error] com.softwaremill.play24.controllers.AnotherController$$anonfun$ResolvedDecoratedAction$1$$anonfun$apply$5$$anonfun$apply$6.apply(CoffeeController.scala:64)

I could try running(FakeApplication()){...} but then I get routes injector errors.我可以尝试 running(FakeApplication()){...} 但随后我遇到了路由注入器错误。 Currently the code uses routesGenerator := InjectedRoutesGenerator in the build.sbt, but I don't think it translates over into test phase.目前,代码在 build.sbt 中使用了 routesGenerator := InjectedRoutesGenerator,但我认为它不会转化为测试阶段。

I have put the code up on here https://github.com/tashiscool/Play24MacwireMockingFailure我已经把代码放在这里https://github.com/tashiscool/Play24MacwireMockingFailure

If you run activator test you should see the errors in the controllers tests.如果您运行激活器测试,您应该会在控制器测试中看到错误。

i ran into the exact same problem.我遇到了完全相同的问题。 i spent a little bit of time looking into it, it appears that via FakeRequest#withSession , you can end up calling some parts of the Crypto library within play that depend on config but have no way to pass in a FakeApplication .我花了一点时间研究它,似乎通过FakeRequest#withSession ,您最终可以调用游戏中依赖于配置但无法传入FakeApplicationCrypto库的某些部分。

...but i did find a simple workaround that might work for you as well. ...但我确实找到了一个可能对您也有用的简单解决方法。 basically just wrapping FakeRequest with a mockito spy, and then stubbing the methods that try to call the internal Crypto API.基本上只是用FakeRequest间谍包装FakeRequest ,然后存根尝试调用内部Crypto API 的方法。

import org.mockito.Mockito.{doReturn, spy}
import play.api.mvc.{AnyContentAsEmpty, Session}
import play.api.test.FakeRequest

trait AuthSupport { 

  def fakeRequest(): FakeRequest[AnyContentAsEmpty.type] = {
    val request = spy(FakeRequest())
    doReturn(Session(Map("userId" -> "1"))).when(request).session
    request
  }

}

Looks like you didn't configured play secret in application.conf看起来你没有在 application.conf 中配置 play secret
Can you try and define it?你能试着定义它吗?

Look here for more details看这里了解更多详情

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM