我在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
}
}
如果无法对此代码进行单元测试,是否建议采用其他方法进行数据访问?
答案 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 }
...
也许这不是理想的方法,但到目前为止一直在努力。我仍然有兴趣听到任何其他建议。