Пример игры с Macwire в версии 2.4 с расширенными контроллерами
Я взял существующий пример 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
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]
}
Однако, когда я запускаю тесты, я получаю трассировку стека:
[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)
Я мог бы попробовать запустить (FakeApplication()){...}, но затем я получаю ошибки инжектора маршрутов. В настоящее время в коде используются routGenerator:= InjectedRoutesGenerator в build.sbt, но я не думаю, что он переходит в фазу тестирования.
Я разместил код здесь https://github.com/tashiscool/Play24MacwireMockingFailure
Если вы запускаете тест активатора, вы должны увидеть ошибки в тестах контроллеров.
2 ответа
Я столкнулся с точно такой же проблемой. я потратил немного времени на его изучение, кажется, что через FakeRequest#withSession
Вы можете в конечном итоге вызвать некоторые части Crypto
библиотека в игре, которые зависят от конфигурации, но не имеют возможности передать в FakeApplication
,
... но я нашел простой обходной путь, который мог бы работать и для вас. в основном просто упаковка 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
}
}
Похоже, вы не настроили игровой секрет в application.conf
Можете ли вы попытаться определить это?
Смотрите здесь для более подробной информации