Some of my controllers rely on DB connection and structured as follows:
def getAll(revId: Muid) = Action { implicit request =>
DB.withConnection { implicit connection =>
...
I am trying to create a unit test for it with all mocked dependencies, including the connection as well. Now, injection of dependencies is easily done through Guice. However, I am struggling to find a way to mock implicit connection. And, eventually, the test is trying to connect to my default DB in test.
Is it even possible to mock implicits, given this situation, and how?
UPDATE
So, after playing with this thing for a while, I got the following: My class under test:
class ChecklistCreationScheduler @Inject()(jobScheduler: JobScheduler,
dBApi: DBApi,
futureChecklistRepository: FutureChecklistRepository) extends ClassLogger{
def scheduleSingleFutureChecklistJob(futureChecklistId: Muid): Unit = {
logger.info(s"Preparing to schedule one time future checklist job for future checklist id '${futureChecklistId.uuid}'")
val db = dBApi.database("default")
logger.info("Database" + db)
db.withConnection { implicit connection =>
logger.info("Connection" + connection)
...
}
}
}
And the test:
"ChecklistCreationScheduler#scheduleSingleFutureChecklistJob" should {
"schedule a single job through a scheduler" in {
val futureChecklistId = Muid.random()
val jobScheduler = mock[JobScheduler]
val connection = mock[Connection]
val DB = mock[Database]
DB.getConnection returns connection
val dbApi = mock[DBApi]
when(dbApi.database("default")).thenReturn(DB)
val futureChecklistRepository = mock[FutureChecklistRepository]
doReturn(Option.empty).when(futureChecklistRepository).getById(futureChecklistId)(connection)
val chCreationScheduler = new ChecklistCreationScheduler(jobScheduler, dbApi, futureChecklistRepository)
chCreationScheduler.scheduleSingleFutureChecklistJob(futureChecklistId) must throwA[UnexpectedException]
}
}
When I execute the test, it seems like the execution does not even get into the block of withConnection
. (I am never getting to this line: logger.info("Connection" + connection)
).
Any idea?
Here is how you can use Dependency Injection to easily mock the database call:
Considering this is your controller:
package controllers
import javax.inject.Inject
import play.api._
import play.api.db.Database
import play.api.mvc._
class Application @Inject() (database: Database) extends Controller {
def index = Action { implicit request =>
database.withConnection { implicit connection =>
???
}
Ok(views.html.index("Your new application is ready."))
}
}
You can write a Specification like this:
import java.sql.Connection
import controllers.Application
import org.specs2.mutable._
import org.specs2.runner._
import org.junit.runner._
import org.specs2.mock._
import play.api.db.Database
import play.api.mvc.RequestHeader
@RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification with Mockito {
"Application" should {
"index page" in {
val connection = mock[Connection]
val database = mock[Database]
database.getConnection returns connection
val controller = new Application(database)
// You will also need to mock the request
// so that you can add the expected behavior
val request = mock[RequestHeader]
val result = controller.index(request)
// do some assert about your result
result must not beNull
}
}
}
Of course, some other mocks may be necessary to handle your (whole) use case.