将@Transactional 与@Commit 一起使用时,无法测试预期的异常

Wim*_*uwe 5 java junit spring transactions

我正在使用 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;
Run Code Online (Sandbox Code Playgroud)

使用 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"));
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,添加@Transactionalwith 时@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"));
    }
}
Run Code Online (Sandbox Code Playgroud)

但是查看日志记录,DataIntegrityViolationException正在抛出:

2016-05-24 09:05:16.619 ERROR 22790 --- [main] ohengine.jdbc.spi.SqlExceptionHelper:唯一索引或主键违规:“UK_D8HGQ87BS4VPMC81NQ9G69G8X_INDEX_D ON PUBLIC”(JPROBLIC)'PROBLIC. "; SQL 语句:insert into myproject_user (password, username, role, id) values (?, ?, 'ADMIN', ?) [23505-191] 2016-05-24 09:05:16.620 INFO 22790 --- [
main] ohejbinternal.AbstractBatchImpl : HHH000010: 在发布批处理时,它仍然包含 JDBC 语句 2016-05-24 09:05:16.629 WARN 22790 --- [ main] ostest.context.TestContextManager
:在允许 TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@589b3632] 处理“after”执行测试时捕获异常:方法 [public void com.spring.boot.test.user.UserRepositoryIntegrationTest.test()] ,实例 [com.spring.boot.test.user.UserRepositoryIntegrationTest@3ca278bc],异常 [java.lang.AssertionError: 预期异常:org.springframework.dao.DataIntegrityViolationException]

为什么测试失败?会不会是 JUnit 在 Spring 提交事务之前检查异常是否抛出?

Sam*_*nen 5

你不需要承诺。您只需要将工作单元刷新到数据库即可查看DataIntegrityViolationException.

这在Spring 参考手册中关于“误报”的注释中有所描述。但是请注意,EntityManager必须通过@PersistenceContext(not @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();
    }
}
Run Code Online (Sandbox Code Playgroud)

问候,

Sam(Spring TestContext Framework 的作者