差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

次のリビジョン
前のリビジョン
study:java:powermock:mocking [2020/03/26 07:50] – 作成 bananastudy:java:powermock:mocking [2020/05/12 01:19] (現在) – [Mock Protected Parent Method] banana
行 1: 行 1:
-test+====== Mocking Example ====== 
 +%%PowerMock%%を利用したexampleを残しておく。 
 + 
 +===== Mocking Constructor ===== 
 +target classのコードの一部を次に示す。 
 +<code java> 
 +public class SomeActionForm extends AbstractActionForm { 
 +    ~~中略~~ 
 +    //***** public method ***** 
 +    @Override 
 +    public ActionErrors validate(ActionMapping arg0, HttpServletRequest arg1) { 
 +        ActionErrors _errors = new ActionErrors(); 
 + 
 +        //do something 
 + 
 +        return _errors; 
 +    } 
 +
 +</code> 
 + 
 +このクラスは、struts1の%%ActionForm%%クラスの一部である。\\ 
 +異常系テストとして、validationエラーメッセージを確認するために、%%ActionErrors%%クラスをmockしたいケースである。\\ 
 +mockitoでは、constructorのmockクラスを作成できないため、%%PowerMock%%を利用する。\\ 
 + 
 +テストクラスコードの一部を次に示す。 
 +<code java> 
 +@PrepareForTest({SomeActionForm.class}) 
 +public class TestSomeActionForm extends AbstractScreenTestCase { 
 +    ~~中略 
 +    private void doCommonValidate(SomeActionForm form, List<String> errorCodeList) throws Exception { 
 +        ~~中略 
 +        //mock ActionErrors 
 +        ActionErrors _mockActionErrors = mock(ActionErrors.class); 
 +        //new instanceで生成されるActionErrosインスタンスをmock objectに変換 
 +        whenNew(ActionErrors.class).withNoArguments().thenReturn(_mockActionErrors); 
 +        ~~中略 
 +    } 
 +
 +</code> 
 + 
 +ここで注意したい部分は、%%@PrepareForTest%%だ。\\ 
 +テスト対象クラスではなく、mock対象のConstructorが存在するクラスを指定する。\\ 
 +複数個所がある場合は、カンマ区切りで指定する。 
 + 
 +これだけでは、%%ActionErrors%%のエラーメッセージが確認できない。\\ 
 +他に%%ArgumetCaptor%%が必要なのだが、次節で説明する。 
 + 
 +===== ArgumentCaptor ===== 
 +前節の続きで、%%ActionErrors%%のエラーメッセージを確認するコードを次に示す。 
 +<code java> 
 +    private void doCommonValidate(SomeActionForm form, List<String> errorCodeList) throws Exception { 
 +        //create Captor instances for ActionError parameters that will be added to the ActionErrors 
 + ArgumentCaptor<ActionError> _actionErrorCaptor = ArgumentCaptor.forClass(ActionError.class); 
 + 
 +        //mock ActionErrors 
 +        ActionErrors _mockActionErrors = mock(ActionErrors.class); 
 +        //new instanceで生成されるActionErrosインスタンスをmock objectに変換 
 +        whenNew(ActionErrors.class).withNoArguments().thenReturn(_mockActionErrors); 
 + 
 +        //call test method 
 + form.validate(actionMapping, request); 
 + 
 + //verify if the call add() to ActionErrors was made 
 + //and capture the ActionError that was passed 
 + verify(_mockActionErrors, atLeastOnce()).add(anyString(), _actionErrorCaptor.capture()); 
 + 
 + //get the capture ActionError and check the set values 
 + List<ActionError> _errors = _actionErrorCaptor.getAllValues(); 
 + 
 + //show error message 
 + for (ActionError _error : _errors) { 
 +        assertTrue(errorCodeList.contains(_error.getKey()), "{unexpected error code = [" + _error.getKey() + "]}"); 
 +     System.out.println(rsc(_error.getKey(), _error.getValues())); 
 + }//for 
 +    } 
 +</code> 
 + 
 +%%ArgumentCaptor%%の基本使い方をを下に示す。\\ 
 +  - 監視したいクラスを%%ArgumentCaptor%%に渡す。 
 +  - テストメソッドをcallする。 
 +  - verifyメソッドで、監視クラスがcallされたかcheckする。 
 +  - %%ArgumentCaptor%%クラスのgetAllValues(複数の場合)か、getValue(単一)を利用して監視クラスを出力する。 
 + 
 +===== Mocking static method ===== 
 +staticメソッドのmockクラスを作成したい場合は、mockStaticメソッドを利用する。\\ 
 +targetクラスの一部を下に示す。 
 +<code java> 
 +public class DocumentShareSendMailService extends AbstractBaseSampleService { 
 +    ~~中略 
 +    @Override 
 +    protected void execute() { 
 +        ~~中略 
 +        ExecutorService _threadPool = Executors.newFixedThreadPool(FIXED_THREAD_CNT); 
 +        AsyncECabinetUploadUtil _util = new AsyncECabinetUploadUtil(_threadPool); 
 +        ~~中略 
 +    } 
 +
 +</code> 
 +%%AysncECabinetUploadUtil%%クラスは、%%ExecutorService%%を使って非同期処理を行うクラスであるが、テストを実行しても実行されてないことに気づく。\\ 
 +本処理では、非同期処理だが、テストの際は同期処理にしたいというケースで、%%ExecutorService%%ではなく、guavaモジュールに含まている%%MoreExecutors%%クラスを利用する。 
 + 
 +テストクラスのコード一部を次に示す。 
 +<code java> 
 +@PrepareForTest({DocumentShareSendMailService.class}) 
 +public class TestDocumentShareSendMailService extends AbstractCustomTestCase { 
 +    ~~中略 
 +    @Override 
 +    protected void prepareSpecific() throws Exception { 
 +        //mock Executors 
 + mockStatic(Executors.class); 
 + //wait until tasks are completed 
 + ExecutorService _mockExecutor = MoreExecutors.newDirectExecutorService(); 
 + when(Executors.newFixedThreadPool(anyInt())).thenReturn(_mockExecutor); 
 +    } 
 +
 +</code> 
 +%%newDirectExecutorService%%メソッドがすぐにtaskを実行する%%ExecutorService%%を返すため、テスト結果が確認できる。 
 + 
 +===== Using an ArgumentCaptor of Collection type  ===== 
 +%%ArgumentCaptor%%にList型を使いたい場合、%%@Captor%%と%%MockitoAnnotations.initMocks%%を利用する。 
 + 
 +次にテストクラスの一部を示す。 
 +<code java> 
 +public class TestPersonService { 
 +    @Captor 
 +    ArgumentCaptor<List<Person>> captor 
 + 
 +    @Before 
 +    public void before() { 
 +        MockitoAnnotations.initMocks(this); 
 +    } 
 + 
 +    @Test 
 +    public void testService001() { 
 +        PersonService service = ... ; 
 + 
 +        service.execute(); 
 + 
 +        verify(service).update(captor.capture()); 
 + 
 +        assertThat(captor.getValue()).isEmpty(); 
 +    } 
 + 
 +
 +</code> 
 + 
 +===== Mock Protected Parent Method  ===== 
 +Parent classにあるprotected methodの振る舞いを定義する例を紹介する。 
 + 
 +親クラスの例を次に示す。 
 +<code java> 
 +package parent; 
 + 
 +public class Parent { 
 + 
 +    protected void foo(String arg1, String arg2) { 
 +        //some logic here 
 +    } 
 +
 +</code> 
 + 
 +子クラスの例を次に示す。 
 +<code java> 
 +package child; 
 + 
 +import parent.Parent; 
 + 
 +public class Child extends Parent { 
 + 
 +    public String bar() { 
 +        //call parent method 
 +        this.foo(); 
 + 
 +        //Child logic here 
 +    } 
 +
 +</code> 
 + 
 +テストクラスの例を次に示す。 
 +<code java> 
 +package child; 
 + 
 +import parent.Parent; 
 +import static org.mockito.Matchers.anyObject; 
 +import static org.powermock.api.mockito.PowerMockito.doNothing; 
 +import static org.powermock.api.mockito.PowerMockito.spy; 
 +import static org.powermock.api.mockito.PowerMockito.when; 
 +import org.powermock.core.classloader.annotations.PrepareForTest; 
 + 
 +@PrepareForTest({Parent.class, Child.class}) 
 +public class ChildTest { 
 +    //Class Under Test 
 +    Child cut; 
 + 
 +    @Before 
 +    public void setUp() throws Exception { 
 +        //Partial mock to mock methods in parent class 
 +        cut = spy(new Child()); 
 + 
 +        //stub parent foo method 
 +        doNothing().when(cut, "foo", anyObject(), anyObject()); 
 +    } 
 + 
 +    @Test 
 +    public void testBar() { 
 +        //call test method 
 +        cut.bar(); 
 +        //assertion here 
 +    } 
 +
 + 
 +</code> 
 +ここでは、親クラスのfooメソッドが呼ばれた際、何もしない(doNothing)を実装している。 

QR Code
QR Code study:java:powermock:mocking (generated for current page)