Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将@Transactional与@Commit一起使用时无法测试预期的异常_Java_Spring_Junit_Transactions - Fatal编程技术网

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

Java 将@Transactional与@Commit一起使用时无法测试预期的异常,java,spring,junit,transactions,Java,Spring,Junit,Transactions,我使用的是Spring Boot 1.4.0.M3 我有一个@实体,它有一个用户名,应该是唯一的: @NotNull @Column(unique = true) @Pattern(regexp = "[a-zA-Z_\\-\\.0-9]+") @Size(min = 1, max = 30) private String username; 使用Spring数据存储库,我想测试使用重复用户名时是否会出现异常。该测试工作如下: @SpringBootTest @RunWith(SpringRu

我使用的是Spring Boot 1.4.0.M3

我有一个
@实体
,它有一个
用户名
,应该是唯一的:

@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错误22790---[main] o、 h.engine.jdbc.spi.SqlExceptionHelper:唯一索引或主键 违规行为:“UK_D8HGQ87BS4VPMC81NQ9G69G8X_索引打开” PUBLIC.MYPROJECT_用户(用户名)值('wim',1');SQL语句: 在myproject_用户(密码、用户名、角色、id)中插入值(?, [23505-191]2016-05-2409:05:16.620信息22790---[
main]o.h.e.j.b.internal.AbstractBatchImpl:HH000010:发布时 它仍然包含JDBC语句2016-05-24 09:05:16.629 警告22790---[main]o.s.test.context.TestContextManager

:允许TestExecutionListener时捕获异常 [org.springframework.test.context.transaction。TransactionalTestExecutionListener@589b3632] 为测试处理“之后”执行:方法[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提交事务之前检查是否抛出异常?

根据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();
    }
}

请注意,两个静态方法都需要调用才能正常工作。

您不需要提交。您只需将工作单元刷新到数据库中,即可查看
DataIntegrityViolationException

本手册中关于“误报”的说明对此进行了说明。但是,请注意,
EntityManager
必须通过
@PersistenceContext
注入(而不是
@Autowired

以下内容对您来说应该很好:

@RunWith(SpringRunner.class)
@春靴测试
@交易的
公共类UserRepositoryIntegrationTest{
@自动连线
用户存储库;
@持久上下文
实体管理器实体管理器;
@测试(预期=DataIntegrityViolationException.class)
公开无效测试(){
save(User.createAdmin(repository.nextId(),“wim”,“123456”);
save(User.createAdmin(repository.nextId(),“wim”,“123456”);
entityManager.flush();
}
}
问候,


Sam(SpringTestContext框架的作者)

我需要在MVC控制器测试(
@WebAppConfiguration
)中测试
DataIntegrityViolationException
),并通过
@ControllerAdvice
在应用程序内部进行
@ResponseStatus
修改。所以你的方法不适合我,太晚了。不幸的是,
@NotTransactional
注释在Spring4中被排除在外,所以我只是将
@Transactional
和NotTransactional的测试分开。另见

@不推荐使用NotTransactional

更新。2种解决方案:

  • 明确区分事务性测试和非事务性测试
  • 在不需要事务的地方使用
    @Transactional(propagation=propagation.NEVER)

这是意料之中的。。。该异常将在事务提交后发生。事务在方法结束后提交。所以在检查的时候基本上没有例外。您使用此更改了测试的行为。您需要在方法内部提交。“允许TestExecutionListener时捕获异常”说明了一切。您希望提交,但希望断言提交失败。JUnit和Spring彼此都不知道,所以不能对这些东西使用JUnit断言。正如Martin所说,在测试中使用
TestTransaction#end
。感谢您指向该类。我不知道它的存在。我已经添加了一个完整工作版本的答案。这不是问题的答案。你可以在回答中加上这句话作为评论,或者就这个问题单独提问。是的,我同意你的看法。但这对和你有同样问题的人来说是个不错的选择。很好,你让我度过了美好的一天,这是一个完美的答案,简短而甜蜜