在@Commit

时间:2016-05-24 07:12:09

标签: java spring junit 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;

使用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提交事务之前检查是否抛出了异常吗?

3 个答案:

答案 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而不是事务性。另请参阅

中的http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/testing.html#integration-testing-annotations
  

不推荐使用@NotTransactional

更新。 2种方式解决方案:

  • 明确地为Transactional和非事务
  • 分隔您的测试
  • 使用不需要交易的@Transactional(propagation = Propagation.NEVER)