Mockito&PowerMockの使い方編

14684 ワード

なぜmock?


Mockテストとは、テスト中に、HttpServletRequestがServletコンテナで作成されるように構築しにくいオブジェクトや、JDBCのResultSetオブジェクトのような複雑なオブジェクトを容易に取得できないオブジェクトについて、テストのためのテスト方法を仮想オブジェクト(Mockオブジェクト)で作成することです.
以下の使用カテゴリー
  • 実際のオブジェクトは不確定な行為を有し、予測不可能な効果(株価相場、天気予報など)
  • を生じる.
  • リアルオブジェクトが作成しにくい
  • 実際のオブジェクトのいくつかの動作は、
  • をトリガすることが困難である.
  • 実際のオブジェクトは実際には存在しない(他の開発チームや新しいハードウェアと付き合う)など
  • .

    Mockito

  • 公式文書
  • Java Mockライブラリの多く、例えばEasyMockまたはJMockはexpect-run-verify(所望-実行-検証)方式であり、Mockitoはより簡単で直感的な方法を使用する:
  • expect-run-verify方式はまた、Mockitoが高価な前期起動を準備する必要がないことを意味する.彼らの目標は透明で、開発者が選択した行為のテストに専念できるようにすることです.

  • Mockito使用フロー


    mock-->stub----->run-->verify(オプション)

    mock


    mockオブジェクトを作成するには、次の方法があります.

    1、mock

    //mock creation
     List mockedList = mock(List.class);
    
     //using mock object
     mockedList.add("one");
     mockedList.clear();
    
    Once created, a mock will remember all interactions. Then you can selectively verify whatever interactions you are interested in.

    2、spy

       List list = new LinkedList();
       List spy = spy(list);
    
       //optionally, you can stub out some methods:
       when(spy.size()).thenReturn(100);
    
       //using the spy calls *real* methods
       spy.add("one");
       spy.add("two");
    
       //prints "one" - the first element of a list
       System.out.println(spy.get(0));
    
       //size() method was stubbed - 100 is printed
       System.out.println(spy.size());
    
       //optionally, you can verify
       verify(spy).add("one");
       verify(spy).add("two");
    

    注意:spyオブジェクトは実際のオブジェクトではありません
    public class TestSpy {
    
        @Test
        public void test(){
            List list = new LinkedList();
            List spy = spy(list);
    
            spy.add("one");
    
            doReturn(100).when(spy).size();
    
            //  one
            System.out.println(spy.get(0));
            // 100
            System.out.println(spy.size());
            // 0
            System.out.println(list.size());
            // java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
            System.out.println(list.get(0));
        }
    }
    
    

    3、mockとspyの違い

  • By default, for all methods that return a value, a mock will return either null, a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.(mockを使用して生成するオブジェクトは、すべてのメソッドがmockされ、あるメソッドがstubされない限り、戻り値はデフォルト値)
  • .
  • You can create spies of real objects. When you use the spy then the real methods are called (unless a method was stubbed).(spyが生成するspyオブジェクトを使用し、すべてのメソッドは呼び出したspyオブジェクトの真のメソッドであり、あるメソッドがstubになるまで)
  • 4、Shorthand for mocks creation - @Mock annotation

    public class ArticleManagerTest {
    
           @Mock private ArticleCalculator calculator;
           @Mock private ArticleDatabase database;
           @Mock private UserProvider userProvider;
    
           private ArticleManager manager;
    }
    
    

    注意:上のannotationが有効になるためには、次のいずれかを呼び出す必要があります.
  • MockitoAnnotations.initMocks(testClass);
  • MockitoAnnotations.initMocks(testClass)
    
  • use built-in runner: MockitoJUnitRunner
  • 
     @RunWith(MockitoJUnitRunner.StrictStubs.class)
     public class ExampleTest {
    
         @Mockprivate List list;
    
         @Test
         public void shouldDoSomething() {
             list.add(100);
         }
       }
    
  • MockitoRule.
  •  public class ExampleTest {
    
         //Creating new rule with recommended Strictness setting
         @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
    
         @Mock
         private List list;
    
         @Test
         public void shouldDoSomething() {
             list.add(100);
         }
     }
    

    stub


    1、簡単な例

     //You can mock concrete classes, not just interfaces
     LinkedList mockedList = mock(LinkedList.class);
    
     //stubbing
     when(mockedList.get(0)).thenReturn("first");
     when(mockedList.get(1)).thenThrow(new RuntimeException());
    
     //following prints "first"
     System.out.println(mockedList.get(0));
    
     //following throws runtime exception
     System.out.println(mockedList.get(1));
    
     //following prints "null" because get(999) was not stubbed
     System.out.println(mockedList.get(999));
    
     //Although it is possible to verify a stubbed invocation, usually it's just redundant
     //If your code cares what get(0) returns, then something else breaks (often even before verify() gets executed).
     //If your code doesn't care what get(0) returns, then it should not be stubbed. Not convinced? See here.
     verify(mockedList).get(0);
    
  • Stubbing can be overridden: for example common stubbing can go to fixture setup but the test methods can override it. Please note that overridding stubbing is a potential code smell that points out too much stubbing
  • Once stubbed, the method will always return a stubbed value, regardless of how many times it is called.
  • Last stubbing is more important - when you stubbed the same method with the same arguments many times. Other words: the order of stubbing matters but it is only meaningful rarely, e.g. when stubbing exactly the same method calls or sometimes when argument matchers are used, etc.

  • 2、Argument matchers

     //stubbing using built-in anyInt() argument matcher
     when(mockedList.get(anyInt())).thenReturn("element");
    
     //stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
     when(mockedList.contains(argThat(isValid()))).thenReturn("element");
    
     //following prints "element"
     System.out.println(mockedList.get(999));
    
     //you can also verify using an argument matcher
     verify(mockedList).get(anyInt());
    
     //argument matchers can also be written as Java 8 Lambdas
     verify(mockedList).add(argThat(someString -> someString.length() > 5));
     
    

    3、Stubbing void methods with exceptions

       doThrow(new RuntimeException()).when(mockedList).clear();
    
       //following throws RuntimeException:
       mockedList.clear();
    

    4、Stubbing consecutive calls

    when(mock.someMethod("some arg"))
       .thenThrow(new RuntimeException())
       .thenReturn("foo");
    
     //First call: throws runtime exception:
     mock.someMethod("some arg");
    
     //Second call: prints "foo"
     System.out.println(mock.someMethod("some arg"));
    
     //Any consecutive call: prints "foo" as well (last stubbing wins).
     System.out.println(mock.someMethod("some arg"));
    
     when(mock.someMethod("some arg"))
       .thenReturn("one", "two", "three");
    

    5、Stubbing with callbacks

    when(mock.someMethod(anyString())).thenAnswer(new Answer() {
         Object answer(InvocationOnMock invocation) {
             Object[] args = invocation.getArguments();
             Object mock = invocation.getMock();
             return "called with arguments: " + args;
         }
     });
    
     //the following prints "called with arguments: foo"
     System.out.println(mock.someMethod("foo"));
     
    

    verify


    1、Verifying exact number of invocations / at least x / never

    //using mock
     mockedList.add("once");
    
     mockedList.add("twice");
     mockedList.add("twice");
    
     mockedList.add("three times");
     mockedList.add("three times");
     mockedList.add("three times");
    
     //following two verifications work exactly the same - times(1) is used by default
     verify(mockedList).add("once");
     verify(mockedList, times(1)).add("once");
    
     //exact number of invocations verification
     verify(mockedList, times(2)).add("twice");
     verify(mockedList, times(3)).add("three times");
    
     //verification using never(). never() is an alias to times(0)
     verify(mockedList, never()).add("never happened");
    
     //verification using atLeast()/atMost()
     verify(mockedList, atLeastOnce()).add("three times");
     verify(mockedList, atLeast(2)).add("three times");
     verify(mockedList, atMost(5)).add("three times");
    

    2、Verification in order

    // A. Single mock whose methods must be invoked in a particular order
     List singleMock = mock(List.class);
    
     //using a single mock
     singleMock.add("was added first");
     singleMock.add("was added second");
    
     //create an inOrder verifier for a single mock
     InOrder inOrder = inOrder(singleMock);
    
     //following will make sure that add is first called with "was added first, then with "was added second"
     inOrder.verify(singleMock).add("was added first");
     inOrder.verify(singleMock).add("was added second");
    
     // B. Multiple mocks that must be used in a particular order
     List firstMock = mock(List.class);
     List secondMock = mock(List.class);
    
     //using mocks
     firstMock.add("was called first");
     secondMock.add("was called second");
    
     //create inOrder object passing any mocks that need to be verified in order
     InOrder inOrder = inOrder(firstMock, secondMock);
    
     //following will make sure that firstMock was called before secondMock
     inOrder.verify(firstMock).add("was called first");
     inOrder.verify(secondMock).add("was called second");
    
     // Oh, and A + B can be mixed together at will
    

    3、Making sure interaction(s) never happened on mock

    
     //using mocks - only mockOne is interacted
     mockOne.add("one");
    
     //ordinary verification
     verify(mockOne).add("one");
    
     //verify that method was never called on a mock
     verify(mockOne, never()).add("two");
    
     //verify that other mocks were not interacted
     verifyZeroInteractions(mockTwo, mockThree);
    
    

    4、Finding redundant invocations

     //using mocks
     mockedList.add("one");
     mockedList.add("two");
    
     verify(mockedList).add("one");
    
     //following verification will fail
     verifyNoMoreInteractions(mockedList);
     
    

    partial mocking


    spyオブジェクトは呼び出しリアルメソッドであり,mockのdoCallRealMethodも呼び出しリアルメソッドである.partial mockingを考えたとき、stubの方法の多少に基づいて選択します.
  • spy(すべてがstubを除く)
  • mock doCallRealMethod(すべてが真実ではないstubを除く)
  • doReturn when && when thenReturn

  • when thenReturnは関数を実際に呼び出し、結果を
  • に変更します.
  • doReturn whenは本当に関数を呼び出すことはなく、直接結果を
  • に変更します.
  • public class Jerry {
    
        public boolean go() {
            System.out.println("I say go go go!!");
            return true;
        }
    }
    
    
    public class SpyTest {
    
        @Test
        public void test(){
            Jerry spy = spy(new Jerry());
    
            when(spy.go()).thenReturn(false);
    
            //I say go go go!!
            //false
            System.out.println(spy.go());
    
            doReturn(false).when(spy).go();
    
            //false
            System.out.println(spy.go());
    
        }
    }
    
    

    PowerMock


    Mockitoはセルテストの書き込みプロセスを極めて簡略化できるため、多くの人に自分の仕事に応用されているが、Mockツールは静的関数、構造関数、プライベート関数、Final関数、システム関数のシミュレーションを実現することはできないが、これらの方法は往々にして私たちが大規模なシステムで必要とする機能である.PowerMockはEasyMockおよびMockitoをベースとした拡張機能であり、カスタムクラスローダなどの技術により、PowerMockは前述したすべてのシミュレーション機能を実現し、大規模なシステム上のユニットテストに必須のツールとなっている.
  • クラスの静的方法
  • mockStatic
    public class IdGenerator {
    
        public static long generateNewId() {
           return 100L;
        }
    }
    
    
    public class ClassUnderTest {
    
        public void methodToTest() {
    
            final long id = IdGenerator.generateNewId();
        }
    }
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(IdGenerator.class)
    public class MyTestClass {
    
        @Test
        public  void demoStaticMethodMocking(){
            mockStatic(IdGenerator.class);
            when(IdGenerator.generateNewId()).thenReturn(2L);
            new ClassUnderTest().methodToTest();
    //        verifyStatic();
    
            System.out.println(IdGenerator.generateNewId());
    
    
    
        }
    }
    
    
  • 構造関数
  • whenNew(File.class).withArguments(direcPath).thenReturn(mockDirectory);
    public class DirectoryStructure {
    
        public boolean create(String directoryPath) {
            File directory = new File(directoryPath);
    
            if (directory.exists()) {
                throw new IllegalArgumentException(
                    "\"" + directoryPath + "\" already exists.");
            }
    
            return directory.mkdirs();
        }
    }
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(DirectoryStructure.class)
    public class DirectoryStructureTest {
    
        @Test
        public void createDirectoryStructureWhenPathDoesntExist() throws Exception {
    
            final String direcPath = "mocked path";
            File mockDirectory = mock(File.class);
    
            when(mockDirectory.exists()).thenReturn(false);
            when(mockDirectory.mkdirs()).thenReturn(true);
            whenNew(File.class).withArguments(direcPath).thenReturn(mockDirectory);
    
            Assert.assertTrue(new DirectoryStructure().create(direcPath));
    
            verifyNew(File.class).withArguments(direcPath);
        }
    }
    
  • private&finalメソッド
  • when(underTest, nameOfMethodToMock, input).thenReturn(expected);
    public class PrivatePartialMockingExample {
    
        public String methodToTest() {
            return methodToMock("input");
        }
    
        private String methodToMock(String input) {
            return "REAL VALUE = " + input;
        }
    }
    
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(PrivatePartialMockingExample.class)
    public class PrivatePartialMockingExampleTest {
    
        @Test
        public void demoPrivateMethodMocking() throws Exception {
            final String expected = "TEST VALUE";
            final String nameOfMethodToMock = "methodToMock";
            final String input = "input";
    
            PrivatePartialMockingExample underTest = spy(new PrivatePartialMockingExample());
    
            when(underTest, nameOfMethodToMock, input).thenReturn(expected);
            assertEquals(expected,underTest.methodToTest());
    
            verifyPrivate(underTest).invoke(nameOfMethodToMock,input);
        }
    }
    
    

    リファレンスドキュメント


    http://www.importnew.com/21540.html
    https://www.ibm.com/developerworks/cn/java/j-lo-powermock/index.html