Question

I have some (Scala) code in Play which uses JPA for DB access. Works fine. But I want to unit test my code, which will require using a mock EntityManager. Is this possible?

My test is written in specs2 (by extending PlaySpecification) and is run with JUnit. I am using Mockito to mock the EntityManager. But I would expect to be able to do this with other frameworks.

Here's what my code looks like:

object MyThing {
    def create(...) : MyThing = {
        val newThing = ...
        JPA.withTransaction(new play.libs.F.Function0[Unit]() {
            def apply() = {
                JPA.em().persist(newThing)
            }
        })
        return newThing
    }
}

If it is not possible to unit test this code, is there some alternate approach to data access which is recommended?

Was it helpful?

Solution

Apparently there is no way to use a mock EntityManager here, at least none that I could find. So I had to revise my design.

Will Sargent of Typesafe suggested creating a separate DB persistence subproject on the mailing list: https://groups.google.com/d/msg/play-framework/1u-_JbTIuQg/L5_9o4YCfoMJ. I haven't gone quite that far, but I did find a solution that worked for me by defining a separate DAO interface.

I put all the JPA code into a DAO trait - all the implementation is in there. There's also a companion object to provide a singleton instance. Like so:

trait MyThingDAO {
    def create(...) : MyThing = { ... }
}
object MyThingDAO extends MyThingDAO

Now I change my controllers to traits, with a reference to the DAO left unset. A companion object sets the DAO instance to the singleton object. This avoids making any changes to the routes file (no need to instantiate the controllers). Like so:

trait MyThingController {
    val myThingDao : MyThingDAO
    def myAction = Action { implicit request => ... }
}
object MyThingController {
    val myThingDao = MyThingDAO
}

So everything works easily enough with the standard JPA code when the app is running. But when I want to unit test, I can insert a mock DAO like so (this is using Mockito):

...
val mockDao = mock[MyThingDAO]
val controller = new MyThingController() { val myThingDao = mockDao }
...

Maybe this isn't the ideal approach, but it has been working so far. I would still be interested to hear any other suggestions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top