我正在使用Spring Boot 1.4.0.M3。
我的@Entity
username
应该是唯一的:
@NotNull
@Column(unique = true)
@Pattern(regexp = "[a-zA-Z_\\-\\.0-9]+")
@Size(min = 1, max = 30)
private String username;
使用Spring Data Repository,我想测试在使用重复的用户名时是否会出现异常。此测试有效:
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserRepositoryIntegrationTest {
@Autowired
private UserRepository repository;
@Test(expected = DataIntegrityViolationException.class)
public void test() {
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
}
}
但是,在@Transactional
添加@Commit
时,此测试失败:
@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class UserRepositoryIntegrationTest {
@Autowired
private UserRepository repository;
@Test(expected = DataIntegrityViolationException.class)
@Commit
public void test() {
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
}
}
但是看着日志记录,DataIntegrityViolationException
被抛出:
2016-05-24 09:05:16.619错误22790 --- [主要] o.h.engine.jdbc.spi.SqlExceptionHelper:唯一索引或主键 违规:“UK_D8HGQ87BS4VPMC81NQ9G69G8X_INDEX_D ON PUBLIC.MYPROJECT_USER(USERNAME)VALUES('wim',1)“; SQL语句: 插入myproject_user(密码,用户名,角色,id)值(?, ?,'ADMIN',?)[23505-191] 2016-05-24 09:05:16.620 INFO 22790 --- [
main] o.h.e.j.b.internal.AbstractBatchImpl:HHH000010:发布时 批处理它仍然包含JDBC语句2016-05-24 09:05:16.629 WARN 22790 --- [main] o.s.test.context.TestContextManager
:允许TestExecutionListener时捕获异常 [org.springframework.test.context.transaction.TransactionalTestExecutionListener@589b3632] 处理'after'执行test:method [public void com.spring.boot.test.user.UserRepositoryIntegrationTest.test()], 例 [com.spring.boot.test.user.UserRepositoryIntegrationTest@3ca278bc] exception [java.lang.AssertionError:预期的异常: org.springframework.dao.DataIntegrityViolationException]
为什么测试失败?可能是JUnit在Spring提交事务之前检查是否抛出了异常吗?
答案 0 :(得分:3)
你不需要提交。您只需将工作单元刷新到数据库即可查看DataIntegrityViolationException
。
Spring Reference Manual中对此进行了描述。向下滚动到关于"误报"的注释。但请注意,EntityManager
必须通过@PersistenceContext
(而非@Autowired
)注入。
以下内容适用于您:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class UserRepositoryIntegrationTest {
@Autowired
UserRepository repository;
@PersistenceContext
EntityManager entityManager;
@Test(expected = DataIntegrityViolationException.class)
public void test() {
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
entityManager.flush();
}
}
此致
Sam( Spring TestContext Framework的作者)
答案 1 :(得分:2)
根据M.Deinum和Stephane Nicoll的评论,这是工作版本:
@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class UserRepositoryIntegrationTest {
@Autowired
private UserRepository repository;
@Test(expected = DataIntegrityViolationException.class)
public void test() {
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
repository.save(User.createAdmin(repository.nextId(), "wim", "123456"));
TestTransaction.flagForCommit();
TestTransaction.end();
}
}
请注意,需要调用两个静态方法才能使其正常工作。
答案 2 :(得分:2)
我需要在MVC控制器测试(DataIntegrityViolationException
)中测试@WebAppConfiguration
并在@ResponseStatus
内对应用程序进行@ControllerAdvice
修改。所以你的方法并不适合我,它太晚了。不幸的是,在{4}中排除了@NotTransactional
注释,所以我只是将我的测试分开@Transactional
而不是事务性。另请参阅
不推荐使用@NotTransactional
更新。 2种方式解决方案:
@Transactional(propagation = Propagation.NEVER)