我正在尝试使用 SpringJunit4ClassRunner
通过使用 @Transactional
注释来测试我的 DAO 类,而不会在我完成后留下数据。我的 DAO 类包含(精简):
@Repository
public class IdsFunctionJpaController {
@PersistenceContext
EntityManager em;
public void save(IdsFunction function) {
if (function.getId() == 0) {
create(function);
} else {
update(function);
}
}
@Transactional
private void create(IdsFunction idsFunction) {
try {
em.persist(idsFunction);
}
catch (Exception e) {
System.out.println(e);
} finally {
em.close();
}
}
@Transactional
private void update(IdsFunction function) {
try {
em.merge(function);
} finally {
em.close();
}
}
}
我的起始 JUnit 测试用例是
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"} )
public class IdsFunctionJpaControllerTest {
@Autowired
IdsFunctionJpaController dao;
@Test
@Transactional
public void addFunction() {
IdsFunction function = new IdsFunction();
function.setDescription("Test Function Description");
dao.save(function);
assertTrue(function.getId() != 0);
}
}
我在这里要做的只是测试实体是否已创建,但此测试失败了。如果我删除 @Transactional
注释,则测试通过,但测试实体保留在数据库中。我做错了什么?
问候
最佳答案
代理机制
你在用你的头撞 JDK 代理。
您的 dao.save()
方法是非事务性的,它会尝试调用事务性方法 create()
和 update()
。但是事务性的事情发生在类外的 JDK 代理中,而保存方法已经在类中。
参见 this previous answer of mine供引用。
解决方案:
- 使您的
save()
方法具有事务性 - (更好)根本不要让您的 DAO 具有事务性。事务属于服务层,而不是 DAO 层。
引用:
更新:我被 Dao 方法上令人困惑的 @Transactional
注释误导了。你应该删除它们,它们什么都不做,还会让人感到困惑。
正如您在我上面发布的链接中所读到的,@Transactional
注释仅在它们出现在将从 Spring bean 外部调用的公共(public)方法上时才有效(因此您不能类中的一个方法委托(delegate)给同一类的一个或多个代理方法)。
交易测试
Spring 为事务测试提供了特殊的支持类,如 9.3.5.4 Transaction management 中所述。 .如果你让你的测试类从 AbstractTransactionalJUnit4SpringContextTests
扩展每次测试后都会自动回滚事务。在大多数情况下,这正是您所需要的。
关于spring - JUnit、JPA 和 Spring : How to ensure that unit tests leave database clean on completion,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4919904/