2016-08-18 29 views
4

非同期(@Async)メソッドをmockitoでモックする最善の方法は何ですか?下記の提供するサービス:Mockitoを使ってSpringブートで非同期(@Async)メソッドをモックする方法は?

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

Mockitoの検証以下のように:試験方法上記shouldVerify

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

は常にスローされます。

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. 

私は@Asyncを削除する場合は、上記の例外が起こっていないだろう方法はTaskService.createTaskです。

春ブートバージョン:1.4.0.RELEASE

Mockitoのバージョン:1.10.19

+0

テストの実装全体を提供できますか? createTaskメソッドを持つクラスはスーパークラスですか? – marians27

+0

こんにちはMarians27、私は質問を編集しました。重要な点は、@AsyncアノテーションをTaskServiceクラスから削除すると例外が発生しないことです。 –

+1

'@ Async'アノテーションはaspectjや何か他のものを引き起こしますか?あなたが確認しようとしている 'taskService'インスタンスがどんな面でも変更されていないことは確かですか? – SpaceTrucker

答えて

3

この問題の根本的な原因

3

私たちは1.4.1で修正したいと考えていbug in Spring Bootがあります。問題は、あなたのモックTaskServiceがまだ非同期的に呼ばれていてMockitoを壊しているということです。

TaskServiceのインターフェイスを作成し、それを模擬して問題を回避することができます。実装上で@Async注釈を残しておけば、それだけで動作します。

このような何か:私は何を理解するまで

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

私は一時的なハック解決策としてこれを受け入れるだろう:AspectJのに非同期モードを変更することで問題を修正することを見出し

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 
    } 

} 
+0

奇妙なことに、AspectJへの非同期モードを変更すると、私の問題が修正されました:@EnableAsync(mode = AdviceMode.ASPECTJ) '以下の回答を参照してください。 –

関連する問題