繁体   English   中英

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

[英]How to mock Asynchronous (@Async) method in Spring Boot using Mockito?

使用mockito模拟异步( @Async )方法的最佳方法是什么? 提供以下服务:

@Service
@Transactional(readOnly=true)
public class TaskService {
    @Async
    @Transactional(readOnly = false)
    public void createTask(TaskResource taskResource, UUID linkId) {
        // do some heavy task
    }
}

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

上面的测试方法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.

如果我从TaskService.createTask方法中删除@Async ,则不会发生上述异常。

Spring Boot版本: 1.4.0.RELEASE

Mockito版本:1.10.19

我们希望在1.4.1中修复Spring Boot中的错误 问题是你的模拟TaskService仍然被异步调用,这打破了Mockito。

您可以通过为TaskService创建一个接口并创建一个模拟来解决此问题。 只要你只在实现上留下@Async注释就可以了。

像这样的东西:

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
    }

}

发现通过将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);
    }
}

在我明白这个问题的真正根源之前,我会接受这个暂时的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM