My application uses compile time injection. The loader is defined as follows (code snippet):
class AppLoader extends ApplicationLoader { ...}
class AppComponents (context: Context) extends BuiltInComponentsFromContext(context) {
...
//within this I have created instances of my controller and created a route
lazy val userController = new UserController(userRepository, controllerComponents, silhouetteJWTProvider)
lazy val router = new Routes(httpErrorHandler, homeController,userWSRoutes, countController,asyncController, assets)
}
The UserController
class has a signupUser
Action
@Singleton
class UserController @Inject()(
userRepo: UsersRepository,cc: ControllerComponents, silhouette: Silhouette[JWTEnv])(implicit exec: ExecutionContext) extends AbstractController(cc){
...
def signupUser = silhouette.UserAwareAction.async{ implicit request => {
...
}
}
I want to test the signupUser
Action
but I don't know how to do it. I have created the following spec class but I am stuck at how to write the spec and test it.
class UserControllerSpec extends PlaySpec {
"User signup request with non-JSON body" must {
"return 400 (Bad Request) and the validation text 'Incorrect body type. Body type must be JSON'" in {
//I want to create instance of a `FakeRequest` annd pass it to UserController.signupUser. I should test a Future[Result] which I should then assert.
//How do I get instance of userController which I created in my Apploader? I don't want to repeat/duplicate the code of AppLoader here.
}
}
}
Existing components from your ApplicationLoader
can be directly instantiated within tests. Mixin WithApplicationComponents trait and override def components: BuiltInComponents
:
override def components: BuiltInComponents = new YourComponents(context)
Here is an example implementation of your test:
import org.scalatestplus.play._
import org.scalatestplus.play.components.OneAppPerSuiteWithComponents
import play.api.BuiltInComponents
import play.api.mvc.Result
import play.api.libs.json.Json
import play.api.test.Helpers._
import play.api.test._
import scala.concurrent.Future
class UserControllerSpec extends PlaySpec with OneAppPerSuiteWithComponents {
override def components: BuiltInComponents = new YourComponents(context)
"User signup request with non-JSON body" should {
"return 400 (Bad Request) and the validation text 'Incorrect body type. Body type must be JSON'" in {
val Some(result): Option[Future[Result]] =
route(
app,
FakeRequest(POST, "/signup").withJsonBody(Json.parse("""{"bad": "field"}"""))
)
status(result) mustBe BAD_REQUEST
}
}
}
Helpers.stubControllerComponents
is very useful for unit testing controllers. Here is an example of how it can be used to implement the same test without having to deal with ApplicationLoader
.
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import controllers.UserController
import org.scalatest.mockito.MockitoSugar
import org.scalatestplus.play._
import play.api.libs.json.Json
import play.api.test.Helpers._
import play.api.test._
class UserControllerSpec extends PlaySpec with MockitoSugar {
"User signup request with non-JSON body" should {
"return 400 (Bad Request) and the validation text 'Incorrect body type. Body type must be JSON'" in {
implicit val actorSystem = ActorSystem()
implicit val materializer = ActorMaterializer()
val controller = new UserController(
mock[UsersRepository]
Helpers.stubControllerComponents(playBodyParsers = Helpers.stubPlayBodyParsers(materializer)),
mock[Silhouette[JWTEnv]]
)
val result =
call(
controller.signupUser,
FakeRequest(POST, "/signup").withJsonBody(Json.parse("""{"bad": "field"}"""))
)
status(result) mustBe BAD_REQUEST
}
}
}