有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在使用@Transactional和@Commit时,java无法测试预期的异常

我使用的是Spring Boot 1.4.0。M3

我有一个@Entityusername应该是唯一的:

@NotNull
@Column(unique = true)
@Pattern(regexp = "[a-zA-Z_\\-\\.0-9]+")
@Size(min = 1, max = 30)
private String username;

使用Spring数据存储库,我想测试使用重复用户名时是否会出现异常。这个测试有效:

@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"));
    }
}

但是,当用@Commit添加@Transactional时,该测试失败:

@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 ERROR 22790 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Unique index or primary key violation: "UK_D8HGQ87BS4VPMC81NQ9G69G8X_INDEX_D ON PUBLIC.MYPROJECT_USER(USERNAME) VALUES ('wim', 1)"; SQL statement: insert into myproject_user (password, username, role, id) values (?, ?, 'ADMIN', ?) [23505-191] 2016-05-24 09:05:16.620 INFO 22790 --- [
main] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements 2016-05-24 09:05:16.629 WARN 22790 --- [ main] o.s.test.context.TestContextManager
: Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@589b3632] to process 'after' execution for test: method [public void com.spring.boot.test.user.UserRepositoryIntegrationTest.test()], instance [com.spring.boot.test.user.UserRepositoryIntegrationTest@3ca278bc], exception [java.lang.AssertionError: Expected exception: org.springframework.dao.DataIntegrityViolationException]

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


共 (3) 个答案

  1. # 1 楼答案

    根据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控制器测试(@WebAppConfiguration)中测试DataIntegrityViolationException,并通过@ControllerAdvice在应用程序内部进行@ResponseStatus修改。所以你的方法不适合我,太晚了。不幸的是@NotTransactional注释在Spring 4中被排除在外,所以我只是将@Transactional的测试与事务性测试分开。另见http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/testing.html#integration-testing-annotationsfrom

    @NotTransactional is deprecated

    更新。2种解决方案:

    • 明确区分事务性测试和非事务性测试
    • 在不需要交易的地方使用@Transactional(propagation = Propagation.NEVER)
  3. # 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框架的作者)