[Scala 2.6.0] ControllerComponents in tests

1,318 views
Skip to first unread message

Andy Czerwonka

unread,
Jun 27, 2017, 8:50:38 AM6/27/17
to Play Framework
How can I get the ControllerComponents injected in my controller tests?

Justin du coeur

unread,
Jun 27, 2017, 11:10:34 AM6/27/17
to play-fr...@googlegroups.com
How are you creating your controllers for the tests?  And what sort of Dependency Injection are you using?

If you're using Guice for DI (the default in the Play documentation), your test suite should be inheriting from GuiceOneAppPerSuite or one of its cousins.  If you do that, then IIRC you can just call `app.injector.instanceOf[MyController]` -- that will give you a properly "Guiced" copy of the controller, with ControllerComponents automatically injected.

(Caveat: I'm building a custom Application using GuiceApplicationBuilder myself.  But I believe that, if you don't need any customization, it ought to just work if you inherit from one of the test Suite classes...)

On Tue, Jun 27, 2017 at 8:50 AM, Andy Czerwonka <andy.cz...@gmail.com> wrote:
How can I get the ControllerComponents injected in my controller tests?

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/5c9eec78-23a4-4115-9f81-9efaafea428e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Will Sargent

unread,
Jun 27, 2017, 1:14:30 PM6/27/17
to play-fr...@googlegroups.com
If you are using unit tests, then you should use Helpers.stubControllerComponents():


Also check out the Injecting trait, which lets you use `inject[MyController]` rather than `app.injector.instanceOf[MyController]`

--
Will Sargent
Engineer, Lightbend, Inc.


Andy Czerwonka

unread,
Jun 28, 2017, 8:19:27 AM6/28/17
to Play Framework
Thanks Will, not sure how I missed this. 


On Tuesday, June 27, 2017 at 11:14:30 AM UTC-6, Will Sargent wrote:
If you are using unit tests, then you should use Helpers.stubControllerComponents():


Also check out the Injecting trait, which lets you use `inject[MyController]` rather than `app.injector.instanceOf[MyController]`

--
Will Sargent
Engineer, Lightbend, Inc.


On Tue, Jun 27, 2017 at 8:10 AM, Justin du coeur <jduc...@gmail.com> wrote:
How are you creating your controllers for the tests?  And what sort of Dependency Injection are you using?

If you're using Guice for DI (the default in the Play documentation), your test suite should be inheriting from GuiceOneAppPerSuite or one of its cousins.  If you do that, then IIRC you can just call `app.injector.instanceOf[MyController]` -- that will give you a properly "Guiced" copy of the controller, with ControllerComponents automatically injected.

(Caveat: I'm building a custom Application using GuiceApplicationBuilder myself.  But I believe that, if you don't need any customization, it ought to just work if you inherit from one of the test Suite classes...)
On Tue, Jun 27, 2017 at 8:50 AM, Andy Czerwonka <andy.cz...@gmail.com> wrote:
How can I get the ControllerComponents injected in my controller tests?

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.

Andy Czerwonka

unread,
Jun 28, 2017, 8:49:31 AM6/28/17
to Play Framework
My controller takes a bunch of parameters that I inject using Guice. I would like to replace those with stub implementation. Right now I've created my own TestEnvironmentSpec where I create these stubs, but that prevents me from injecting the controller, I new it up explicitly. At some point I want to move away from DI and just go compile time, but I don't want to conflate that with my upgrade to 2.6.0 so I'd be happy doing whatever makes most sense given I use Guice DI now. With that in mind, what's the idiomatic way to do that? 


On Tuesday, June 27, 2017 at 11:14:30 AM UTC-6, Will Sargent wrote:
If you are using unit tests, then you should use Helpers.stubControllerComponents():


Also check out the Injecting trait, which lets you use `inject[MyController]` rather than `app.injector.instanceOf[MyController]`

--
Will Sargent
Engineer, Lightbend, Inc.


On Tue, Jun 27, 2017 at 8:10 AM, Justin du coeur <jduc...@gmail.com> wrote:
How are you creating your controllers for the tests?  And what sort of Dependency Injection are you using?

If you're using Guice for DI (the default in the Play documentation), your test suite should be inheriting from GuiceOneAppPerSuite or one of its cousins.  If you do that, then IIRC you can just call `app.injector.instanceOf[MyController]` -- that will give you a properly "Guiced" copy of the controller, with ControllerComponents automatically injected.

(Caveat: I'm building a custom Application using GuiceApplicationBuilder myself.  But I believe that, if you don't need any customization, it ought to just work if you inherit from one of the test Suite classes...)
On Tue, Jun 27, 2017 at 8:50 AM, Andy Czerwonka <andy.cz...@gmail.com> wrote:
How can I get the ControllerComponents injected in my controller tests?

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.

Andy Czerwonka

unread,
Jun 28, 2017, 8:56:45 AM6/28/17
to Play Framework
Andy with that, I'm getting the following exception in my controller test

- must fail an attempt without an API key *** FAILED ***
[info]   java.lang.UnsupportedOperationException: NoMaterializer does not provide an ExecutionContext
[info]   at play.api.test.NoMaterializer$.executionContext(Helpers.scala:661)
[info]   at play.api.mvc.PlayBodyParsers.$anonfun$enforceMaxLength$1(BodyParsers.scala:844)
[info]   at akka.stream.impl.Compose.apply(TraversalBuilder.scala:164)
[info]   at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:488)
[info]   at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:424)
[info]   at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:415)
[info]   at akka.stream.scaladsl.RunnableGraph.run(Flow.scala:439)
[info]   at akka.stream.scaladsl.Source.runWith(Source.scala:83)
[info]   at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:203)
[info]   at play.api.test.EssentialActionCaller.call(Helpers.scala:249)

Andy Czerwonka

unread,
Jun 28, 2017, 9:03:13 AM6/28/17
to Play Framework
A little more context...

I create my test app like this given I want to point to a test database

val params = Map(
"tyrion.mongo.database" -> "tyrion_test",
"tyrion.test" -> true
)

val app: play.api.Application = new GuiceApplicationBuilder().configure(params).build()

On Wednesday, June 28, 2017 at 6:49:31 AM UTC-6, Andy Czerwonka wrote:

Will Sargent

unread,
Jun 28, 2017, 10:16:56 AM6/28/17
to play-fr...@googlegroups.com
Can you include the test that's failing?

-- 
Will Sargent

Andy Czerwonka

unread,
Jun 28, 2017, 12:35:20 PM6/28/17
to Play Framework
For sure, I've tried to snip out the noise, the think the significant parts are here...

class DeviceApiSpec extends TestEnvironmentSpec with Results with BeforeAndAfterAll {

"DeviceApi#siteData()" must {

// 1. This is how I create the controller here.. versus injecting it. The params come from the TestEnvironmentSpec
val api = new DeviceApi(components, app.actorSystem, app.configuration, mailer, messenger, messenger, mongo, encryptionService)

val payload = Json.obj(
"location" -> Json.obj("lat" -> 51.235685, "lng" -> -1.309197)
)

lazy val authorizedRequest = FakeRequest(POST, "/api/device")
.withHeaders(AUTHORIZATION -> apikey)

"fail an attempt without an API key" in {
val request = FakeRequest(POST, "/api/device")
.withJsonBody(payload)
val result = call(api.siteData(), request)
status(result) mustBe UNAUTHORIZED
}
}


abstract class TestEnvironmentSpec extends PlaySpec with Injecting with Inside with GuiceOneAppPerSuite with BeforeAndAfterEach {


val params = Map(
"tyrion.mongo.database" -> "tyrion_test",
"tyrion.test" -> true
)

  implicit lazy override val app: play.api.Application = new GuiceApplicationBuilder().configure(params).build()
implicit lazy val materializer: Materializer = app.materializer
implicit lazy val components = Helpers.stubControllerComponents()

implicit val mongo = inject[MongoEnvironment]
implicit val db = mongo.db

val encryptionService = inject[EncryptionService]
val mailer = inject[MockMailer]
val messenger = inject[MockMessenger]
}

and finally

class DeviceApi @Inject()(components: ControllerComponents,
akka: ActorSystem,
config: Configuration,
mailer: Emailer,
@Named("sms") smsMessenger: Messenger,
@Named("voice") voiceMessenger: Messenger,
mongoEnvironment: MongoEnvironment,
es: EncryptionService) extends AuthenticationController(components, mongoEnvironment, es) { ...

Will Sargent

unread,
Jun 28, 2017, 1:03:19 PM6/28/17
to play-fr...@googlegroups.com
Okay -- if you've already got an "app" in scope, you've got a functional test and so you don't need to call stubControllerComponents: you can call inject[ControllerComponents] directly.

--
Will Sargent
Engineer, Lightbend, Inc.


To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/8f5746ae-df88-44da-8847-f8af4aca9754%40googlegroups.com.

Andy Czerwonka

unread,
Jun 28, 2017, 2:36:01 PM6/28/17
to Play Framework
Thanks Will, that did the trick.
Reply all
Reply to author
Forward
0 new messages