所以我有一个有趣的问题,我需要一些帮助。我知道在使用junit的事务中回滚的问题有很多,但我相信我的问题和略有不同。为了让人们更好地理解这个问题,让我从头开始。
我已为用户管理系统实施了 UserManagementService 及其各自的 DAO 。有一种称为CreateUser(User obj)的通用方法,用于创建唯一用户。现在,有一个约束集,电子邮件地址是唯一的,所以如果我们尝试使用已经使用过的电子邮件地址调用此方法,我们会抛出一个名为 UserManagementException 的自定义异常及其各自的错误消息。所有这一切都很好,但是我遇到的问题是单元测试。哦,在我忘记之前,让我提一下我正在使用的软件堆栈[ Java,spring,hibernate ]
我的单元测试类使用Transactional注释为每个实际命中db的方法注释。这些方法还具有@Rollback注释,以便在每次测试调用结束时回滚所有插入,更新和删除。所以我在这里遇到的问题是我想测试唯一的用户约束场景。通过使用具有相同电子邮件地址的用户对象第二次调用createUser(obj),我希望确保抛出UserManagementException异常。但是,由于它是事务性的,因此每当抛出异常时,事务都会在单元测试完成之前回滚,因此测试失败。以下是测试用例。
@Test
@Rollback
@Transactional
public void testUniqueCreateConsoleUser() {
boolean success;
ConsoleUser newUser;
//first one
userManagementDao.createConsoleUser(user);
//second one. This shd throw a UserManagementException
try {
//now try and insert a new user with same email
newUser = new ConsoleUser("Queen", "Kong", "king.kong@blah.com", "kingkong","Universal Studios", "America/Los_Angeles", false, null);
userManagementDao.createConsoleUser(newUser);
//if this passed this is a problem. Console users should have unique email address
success = false;
} catch (UserManagementException e) {
success = true;
}
Assert.assertTrue(success);
}
奇怪的是,当我通过调试器运行它时,Assert.assertTrue()方法被正确调用,但测试最终失败。
我尝试的另一件事是在@Transactional注释中添加道具。我添加了流动的 @Transactional(noRollbackFor = UserManagementException.class),希望如果抛出异常,则不会在测试结束时调用回滚。我可能会以错误的方式接近这一点,因此围绕此类测试的任何想法或最佳实践都会非常昂贵。
注意:下面是stacktrace的片段..
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:695)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspect
答案 0 :(得分:0)
如果你可以确认抛出额外的回滚(例如 - 当spring执行插入时,当它看到它失败时,它是否已经将事务回滚?)那么你应该捕获回滚,或者配置spring not not推回交易。
也就是说,显然,Spring正在实施的回滚与单元测试中的预期回滚相冲突。这种回滚会混淆回滚注释,导致“unit-test / Spring ether”中出现意外抛出异常。
简单的解决方案:不要为此测试启用自动回滚。测试并不总是非常优雅。
答案 1 :(得分:0)
我建议首先从数据库中加载现有用户,然后尝试使用与该用户相同的电子邮件地址插入另一个用户,而不是插入用户,然后插入另一个用户。被找回了。如果是这样,您只需要这样做:
@Test(expected = UserManagementException.class)
public void insert_duplicate_user() throws Exception {
// Read user from database
final ConsoleUser user = dao.load(...);
// Create new user with same email address.
final ConsoleUser newUser = new ConsoleUser (...);
newUser.setEmail(user.getEmail());
// Write
dao.createConsoleUser(newUser);
/*
* If you get here, there is a problem with your DAO logic
* and a new user (with the same email was created).
* So, we need to clean that up
*/
// Delete new user
dao.deleteUser(newUser);
}
除非抛出UserManagementException
,否则此测试将失败。
答案 2 :(得分:0)
从您的示例中很难说,但您似乎正在测试您的实际DAO实现。而不是让单元测试数据击中您的实际数据库,使用模拟实现或模拟框架来模拟您的DAO。然后,您可以以编程方式处理返回的数据,并将其转换为您想要的任何验证方案。