在Play中使用JPA时使用模拟EntityManager进行单元测试

时间:2014-02-26 22:47:05

标签: unit-testing scala playframework playframework-2.2

我在Play中有一些(Scala)代码,它使用JPA进行数据库访问。工作良好。但我想对我的代码进行单元测试,这需要使用模拟EntityManager。这可能吗?

我的测试是用specs2编写的(通过扩展PlaySpecification)并使用JUnit运行。我正在使用Mockito来模拟EntityManager。但我希望能够与其他框架一起做到这一点。

以下是我的代码:

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

如果无法对此代码进行单元测试,是否建议采用其他方法进行数据访问?

1 个答案:

答案 0 :(得分:0)

显然在这里没有办法使用模拟EntityManager,至少没有我能找到的。所以我不得不修改我的设计。

Typesafe的Sargent是否建议在邮件列表上创建一个单独的数据库持久性子项目:https://groups.google.com/d/msg/play-framework/1u-_JbTIuQg/L5_9o4YCfoMJ。我没有走得那么远,但我确实通过定义一个单独的DAO接口找到了一个对我有用的解决方案。

我将所有JPA代码放入DAO特征中 - 所有实现都在那里。还有一个伴随对象来提供单例实例。像这样:

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

现在我将控制器更改为traits,并引用了未设置的DAO。伴随对象将DAO实例设置为单例对象。这样可以避免对routes文件进行任何更改(无需实例化控制器)。像这样:

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

因此,当应用程序运行时,所有内容都可以使用标准JPA代码轻松完成。但是当我想进行单元测试时,我可以像这样插入一个模拟DAO(这是使用Mockito):

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

也许这不是理想的方法,但到目前为止一直在努力。我仍然有兴趣听到任何其他建议。