与交易模板集成测试手动交易

spa*_*pan 5 java unit-testing mockito spring-transactions

当我尝试测试使用手动事务的方法时,我的事务模板上出现空指针异常。当我在 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());
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用模拟模板并像这样注入它:

@Mock
private TransactionTemplate transactionTemplate;

@InjectMocks
private MyClass myClass;
Run Code Online (Sandbox Code Playgroud)

我还尝试用以下方式注释我的测试:

@RunWith(SpringJUnit4ClassRunner.class)
Run Code Online (Sandbox Code Playgroud)

调试此配置时,模板实际上已注入并且不再为空。但由于我有兴趣测试交易中的操作,我不想模拟它,所以我使用:

when(transactionTemplate.execute(Mockito.any())).thenCallRealMethod();
Run Code Online (Sandbox Code Playgroud)

这会引发一个新的空指针异常,因为事务模板尝试使用 TransactionManager 并且它仍然为空。

如何在交易模板内对我的方法调用进行单元测试?

Mar*_*Eis 6

我通常所做的不是调用真正的方法,而是只是模拟真实的行为。在模拟中调用真实方法将会失败,因为模拟不在 springs 注入上下文中进行管理。好吧,准确地说,您可以通过将它们添加到测试配置(普通 SpringMVC)或使用 @MockBean(spring boot)来使它们存在于注入上下文中。但它们仍然只是作为依赖项注入。但不会收到任何依赖项。对于单元测试来说,这通常是所需的行为。

所以只需做类似的事情:

when(_transactionTemplate.execute(any())).thenAnswer(invocation -> invocation.<TransactionCallback<Boolean>>getArgument(0).doInTransaction(_transactionStatus));
Run Code Online (Sandbox Code Playgroud)

_transactionStatus 本身可以是一个模拟,用于测试回调内状态的使用情况。

模拟就是模拟的用途:)