Java 集成测试手动事务与事务模板
当我尝试测试使用手动事务的方法时,我的事务模板上出现空指针异常。当我在Spring Boot中运行应用程序时,它会按预期工作Java 集成测试手动事务与事务模板,java,unit-testing,mockito,spring-transactions,Java,Unit Testing,Mockito,Spring Transactions,当我尝试测试使用手动事务的方法时,我的事务模板上出现空指针异常。当我在Spring Boot中运行应用程序时,它会按预期工作 @Autowired TransactionTemplate template; public CompletableFuture<MyResultEntity> addToA(BInput input) { return CompletableFuture .supplyAsync( () -> tem
@Autowired
TransactionTemplate template;
public CompletableFuture<MyResultEntity> addToA(BInput input) {
return CompletableFuture
.supplyAsync(
() -> template.execute(status -> {
A a = aRepository.findOne(input.getA());
List<B> addedBs = saveBs(input.getB(), a);
return new MyResultEntity(a, addedBs);
}), MyCustomExecutor());
}
我还尝试用以下内容注释我的测试:
@RunWith(SpringJUnit4ClassRunner.class)
调试此配置时,模板实际上被注入,不再为null。但是,由于我对测试事务中的操作感兴趣,我不希望对其进行模拟,因此我使用:
when(transactionTemplate.execute(Mockito.any())).thenCallRealMethod();
但这会引发新的空指针异常,因为事务模板尝试使用TransactionManager,但该异常仍然为空
如何在事务模板内部对方法调用进行单元测试?如果
TransactionManager
为null
,则表示Spring可能没有在测试上下文中加载所有必要的依赖项。无论如何,如果需要调用
execute()
方法,为什么要模拟TransactionTemplate
您的测试看起来像是集成/社交测试,而不是单元测试。如果是这样的话,你不需要嘲笑任何事情。
如果您想编写一个单元测试来测试
addToA()
方法中的实际逻辑,那么应该使用mock而不是部分mock。供应商中使用的模拟依赖项提供并断言返回了预期的
MyResultEntity
实例
请注意,单元测试的值是有限的,并且可能被认为是脆弱的,因为它只断言调用了一系列方法。通常,您希望根据更具体的逻辑(如计算/提取/转换)来断言行为
以下是一个示例(未经测试,但应给出一个思路):
@Mock
存储库是positorymock;
@嘲弄
存储库BRepositoryMock;
@试验
public void addToA()引发异常{
BInput输入=新的BInput();
//记录模仿行为
A aMockByRepository=Mockito.mock(A.class);
List listBMockByRepository=new arrayList();
Mockito.when(ARepositoryMock.findOne(input.getA())。然后返回(aMockByRepository);
Mockito.when(BRepositoryMock.saveBs(input.getB(),aMockByRepository)),然后返回(listBMockByRepository);
//行动
CompletableFuture=myObjectUnderTest.addToA(输入);
//断言
MyResultEntity actualResultEntity=future.get();
Assert.assertEquals(aMockByRepository,actualResultEntity.getA());
Assert.assertEquals(listBMockByRepository,actualResultEntity.getListOfB());
}
我通常不会调用实际方法,而是模拟实际行为。在mock中调用real方法将失败,因为mock不是在springs注入上下文中管理的。确切地说,您可以通过将它们添加到测试配置(纯SpringMVC)或使用@MockBean(SpringBoot)使它们存在于注入上下文中。但它们仍然只是作为依赖项注入的。但不会收到任何依赖项。对于单元测试,这通常是期望的行为
所以,只要做一些类似的事情:
when(_transactionTemplate.execute(any())).thenAnswer(invocation -> invocation.<TransactionCallback<Boolean>>getArgument(0).doInTransaction(_transactionStatus));
when(_transactionTemplate.execute(any())。然后回答(invocation->invocation.getArgument(0).doInTransaction(_transactionStatus));
_transactionStatus本身可以是一个模拟,用于测试回调中状态的使用情况
mock是mock的用途:)它是一种集成测试。我会尽快研究解决方案。
@Mock
Repository ARepositoryMock;
@Mock
Repository BRepositoryMock;
@Test
public void addToA() throws Exception {
BInput input = new BInput();
// record mock behaviors
A aMockByRepository = Mockito.mock(A.class);
List<B> listBMockByRepository = new arrayList<>();
Mockito.when(ARepositoryMock.findOne(input.getA())).thenReturn(aMockByRepository);
Mockito.when(BRepositoryMock.saveBs(input.getB(), aMockByRepository)).thenReturn(listBMockByRepository);
// action
CompletableFuture<MyResultEntity> future = myObjectUnderTest.addToA(input);
//assertion
MyResultEntity actualResultEntity = future.get();
Assert.assertEquals(aMockByRepository, actualResultEntity.getA());
Assert.assertEquals(listBMockByRepository, actualResultEntity.getListOfB());
}
when(_transactionTemplate.execute(any())).thenAnswer(invocation -> invocation.<TransactionCallback<Boolean>>getArgument(0).doInTransaction(_transactionStatus));