我正在JUnit
为消息驱动的Pojo(MDP)编写集成测试:
@JmsListener(destination = "jms/Queue", containerFactory = "cf")
public void processMessage(TextMessage message) throws JMSException {
repo.save(new Entity("ID"));
}
其中repo
是spring-data
存储库
我的单元测试:
@Test
public void test() {
//sendMsg
sendJMSMessage();
//verify DB state
Entity e = repo.findOne("ID");
assertThat(e, is(notNullValue()) );
}
现在,问题是processMessage()
方法在与test()
方法不同的线程中执行,因此我发现我需要以某种方式等待processMessage()
方法在验证DB的状态之前完成。我能找到的最佳解决方案是基于CountDownLatch。所以现在方法看起来像这样:
@JmsListener(destination = "jms/Queue", containerFactory = "cf")
public void processMessage(TextMessage message) throws JMSException {
repo.save(new Entity("ID"));
latch.countDown();
}
和测试
@Test
public void test() {
//set the countdownlatch
CountDownLatch latch = new CountDownLatch(1);
JMSProcessor.setLatch(latch);
//sendMsg
sendJMSMessage();
try {
countDownLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//verify DB state
Entity e = repo.findOne("ID");
assertThat(e, is(notNullValue()) );
}
所以我为自己感到骄傲,然后我进行了测试而失败了。 repo.findOne("ID")
返回null
。在第一个反应中,我在该行设置了一个断点并继续进行调试。在调试会话期间,repo.findOne("ID")
实际返回了@JMSListener
侦听器方法插入的实体。
在我的头脑中搔了一会儿之后的当前理论:由于spring-data
存储库是在两个不同的线程中访问的,因此它获得了两个不同的EntityManager
实例,因此它们是两个线程处于不同的交易中。尽管使用CountDownLatch
进行了某种同步,但当JUnit @JMSListener
带注释的方法启动新的时,绑定到执行@Test
带注释的方法的线程的事务尚未提交事务并尝试检索实体。
所以我的问题是:
EntityManager
)