简体   繁体   English

如何使用Mockito模拟Spring Boot中的异步(@Async)方法?

[英]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.

相关问题 使用Spring Boot和Mockito进行模拟对象方法调用 - Mock object method call using Spring Boot and Mockito 如何使用 Spring Boot 和 mockito 模拟 JSON 文档以进行测试 - How to mock a JSON document for test using spring boot and mockito 如何使用 Mockito 模拟 spring 引导的这段代码? - How to mock this piece of code of spring boot using Mockito? 无法使用 Mockito 在 Spring 引导中模拟 AWSSecretsManager - Unable to mock AWSSecretsManager in Spring boot using Mockito 如何使用 Spring Security 和 Mockito 模拟 AuthenticationManager 身份验证方法 - How to mock AuthenticationManager authenticate method using Spring Security and Mockito 如何使用 Mockito 模拟此方法 - How to mock this method using Mockito 使用Mockito模拟Spring的LocalContainerEntityManagerFactoryBean方法? - Mock spring's LocalContainerEntityManagerFactoryBean method using Mockito? 我无法在Spring Boot应用程序中使用Mockito模拟Dao方法 - I am not able to mock the Dao method using mockito in Spring boot application 如何使用 Mockito 和 JUnit 在 Spring 引导中测试 DELETE 方法 - How to test DELETE method in Spring boot using Mockito and JUnit 使用 mockito 和 spring 模拟的 authowired bean 的模拟方法 - Mock Method of authowired bean using mockito and spring mock
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM