Skip to content

Commit

Permalink
Add Injecting trait (#6661)
Browse files Browse the repository at this point in the history
  • Loading branch information
wsargent authored and gmethvin committed Oct 25, 2016
1 parent 5c52241 commit b3d2ce5
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 0 deletions.
Expand Up @@ -31,6 +31,17 @@ protected Application provideApplication() {
return Helpers.fakeApplication();
}

/**
* Provides an instance from the application.
*
* @param clazz the type's class.
* @param <T> the type to return, using `app.injector.instanceOf`
* @return an instance of type T.
*/
<T> T inject(Class<T> clazz) {
return app.injector().instanceOf(clazz);
}

@Before
public void startPlay() {
app = provideApplication();
Expand Down
19 changes: 19 additions & 0 deletions framework/src/play-test/src/main/scala/play/api/test/Helpers.scala
Expand Up @@ -22,6 +22,7 @@ import play.twirl.api.Content
import scala.concurrent.{ Await, Future }
import scala.concurrent.duration._
import scala.language.reflectiveCalls
import scala.reflect.ClassTag

/**
* Helper functions to run tests.
Expand Down Expand Up @@ -441,6 +442,24 @@ object Helpers extends PlayRunners
with RouteInvokers
with FutureAwaits

/**
* A trait declared on a class that contains an `def app: Application`, and can provide
* instances of a class. Useful in integration tests.
*/
trait Injecting {
self: HasApp =>

/**
* Given an application, provides an instance from the application.
*
* @tparam T the type to return, using `app.injector.instanceOf`
* @return an instance of type T.
*/
def inject[T: ClassTag]: T = {
self.app.injector.instanceOf
}
}

/**
* In 99% of cases, when running tests against the result body, you don't actually need a materializer since it's a
* strict body. So, rather than always requiring an implicit materializer, we use one if provided, otherwise we have
Expand Down
Expand Up @@ -11,4 +11,12 @@ package object test {
* Provided as an implicit by WithServer and WithBrowser.
*/
type Port = Int

/**
* A structural type indicating there is an application.
*/
type HasApp = {
def app: Application
}

}
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2009-2016 Lightbend Inc. <https://www.lightbend.com>
*/
package play.test;

import org.junit.Test;
import play.i18n.MessagesApi;

import static org.junit.Assert.assertNotNull;

/**
* Tests WithApplication functionality.
*/
public class WithApplicationTest extends WithApplication {

@Test
public void withInject() {
MessagesApi messagesApi = inject(MessagesApi.class);
assertNotNull(messagesApi);
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2009-2016 Lightbend Inc. <https://www.lightbend.com>
*/
package play.api.test

import org.specs2.mock.Mockito
import org.specs2.mutable._
import play.api.Application
import play.api.inject.Injector

import scala.language.reflectiveCalls

class InjectingSpec extends Specification with Mockito {

class Foo

class AppContainer(val app: Application)

"Injecting trait" should {

"provide an instance when asked for a class" in {
val injector = mock[Injector]
val app = mock[Application]
app.injector returns injector
val expected = new Foo
injector.instanceOf[Foo] returns expected

val appContainer = new AppContainer(app) with Injecting
val actual: Foo = appContainer.inject[Foo]
actual must_== expected
}
}
}

0 comments on commit b3d2ce5

Please sign in to comment.