Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.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 集成测试手动事务与事务模板_Java_Unit Testing_Mockito_Spring Transactions - Fatal编程技术网

Java 集成测试手动事务与事务模板

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

当我尝试测试使用手动事务的方法时,我的事务模板上出现空指针异常。当我在Spring Boot中运行应用程序时,它会按预期工作

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