[英]How to mock Asynchronous (@Async) method in Spring Boot using Mockito?
What is the best way to mock asynchronous ( @Async
) method with mockito? 使用mockito模拟异步( @Async
)方法的最佳方法是什么? Provided service below: 提供以下服务:
@Service
@Transactional(readOnly=true)
public class TaskService {
@Async
@Transactional(readOnly = false)
public void createTask(TaskResource taskResource, UUID linkId) {
// do some heavy task
}
}
Mockito's verification as below: Mockito的验证如下:
@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {
@Autowired
MockMvc mockMvc;
@MockBean
private TaskService taskService;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
// other details omitted...
@Test
public void shouldVerify() {
// use mockmvc to fire to some controller which in turn call taskService.createTask
// .... details omitted
verify(taskService, times(1)) // taskService is mocked object
.createTask(any(TaskResource.class), any(UUID.class));
}
}
The test method shouldVerify
above will always throw: 上面的测试方法shouldVerify
总是抛出:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced argument matcher detected here:
-> at SomeTest.java:77) // details omitted
-> at SomeTest.java:77) // details omitted
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
The exception above won't happend if I remove @Async
from the TaskService.createTask
method. 如果我从TaskService.createTask
方法中删除@Async
,则不会发生上述异常。
Spring Boot version: 1.4.0.RELEASE Spring Boot版本: 1.4.0.RELEASE
Mockito version: 1.10.19 Mockito版本:1.10.19
There's a bug in Spring Boot that we hope to fix in 1.4.1. 我们希望在1.4.1中修复Spring Boot中的错误 。 The problem is that your mock TaskService
is still being called asynchronously which breaks Mockito. 问题是你的模拟TaskService
仍然被异步调用,这打破了Mockito。
You could work around the problem by creating an interface for TaskService
and creating a mock of that. 您可以通过为TaskService
创建一个接口并创建一个模拟来解决此问题。 As long as you leave the @Async
annotation only on the implementation things will then work. 只要你只在实现上留下@Async
注释就可以了。
Something like this: 像这样的东西:
public interface TaskService {
void createTask(TaskResource taskResource, UUID linkId);
}
@Service
@Transactional(readOnly=true)
public class AsyncTaskService implements TaskService {
@Async
@Transactional(readOnly = false)
@Override
public void createTask(TaskResource taskResource, UUID linkId) {
// do some heavy task
}
}
Found out that by changing the Async mode to AspectJ fixed the issue: 发现通过将Async模式更改为AspectJ修复了问题:
@EnableCaching
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(lazyInit = true)
@EnableAsync(mode = AdviceMode.ASPECTJ) // Changes here!!!
public class Main {
public static void main(String[] args) {
new SpringApplicationBuilder().sources(Main.class)
.run(args);
}
}
I'll accept this as a temporary hackish solution until I understand what's the real root cause of this issue. 在我明白这个问题的真正根源之前,我会接受这个暂时的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.