#author("2021-08-11T22:50:40+09:00","","") #author("2021-08-11T22:58:41+09:00","","") [[ソフトウェア開発>SoftwareEngineering]] / [[Java>../]] / [[Mockito>./]] *Mockito [#xfb22e90] #contents **1. Let's verify some behaviour! [#xb5bc6fb] #highlightjs([java]) package org.codereign.mockito.tutorial.tutorial01; import static org.mockito.Mockito.*; import java.util.List; import org.junit.Test; public class Tutorial01Test { @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void test() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- List mockedList = mock(List.class); // --------------------------------------------------------- // Act // --------------------------------------------------------- mockedList.add("one"); mockedList.clear(); // --------------------------------------------------------- // Assert // --------------------------------------------------------- verify(mockedList).add("one"); verify(mockedList).clear(); } } **2. How about some stubbing? [#qa8343cd] #highlightjs([java]) package org.codereign.mockito.tutorial.tutorial02; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import java.util.LinkedList; import org.junit.jupiter.api.Test; public class Tutorial02Test { @SuppressWarnings("rawtypes") @Test public void test1() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- LinkedList mockedList = mock(LinkedList.class); when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException()); // --------------------------------------------------------- // Act // --------------------------------------------------------- Object actual = mockedList.get(0); // --------------------------------------------------------- // Assert // --------------------------------------------------------- assertEquals("first", actual); verify(mockedList).get(0); } @SuppressWarnings("rawtypes") @Test public void test2() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- LinkedList mockedList = mock(LinkedList.class); when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException()); // --------------------------------------------------------- // Act & Assert // --------------------------------------------------------- try { mockedList.get(1); fail("RuntimeException が発生する想定のため到達不可能なはず"); } catch (Exception e) { assertTrue(e instanceof RuntimeException); } verify(mockedList).get(1); } @SuppressWarnings("rawtypes") @Test public void test3() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- LinkedList mockedList = mock(LinkedList.class); when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException()); // --------------------------------------------------------- // Act // --------------------------------------------------------- Object actual = mockedList.get(999); // --------------------------------------------------------- // Assert // --------------------------------------------------------- assertNull(actual); verify(mockedList).get(999); } } **3. Argument matchers [#df7de0d0] **4. Verifying exact number of invocations / at least once / never [#g5036188] #highlightjs([java]) package org.codereign.mockito.tutorial.tutorial04; import static org.mockito.Mockito.*; import java.util.List; import org.junit.Test; /** * 呼び出し回数を検証します。 */ public class Tutorial04Test { @SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void test() { // --------------------------------------------------------- // Arrange // --------------------------------------------------------- List mockedList = mock(List.class); // --------------------------------------------------------- // Act // --------------------------------------------------------- mockedList.add("once"); mockedList.add("twice"); mockedList.add("twice"); mockedList.add("three times"); mockedList.add("three times"); mockedList.add("three times"); // --------------------------------------------------------- // Assert // ....呼び出し回数が想定していた回数と一致しているか検証する // --------------------------------------------------------- verify(mockedList, times(0)).add("never happened"); verify(mockedList, times(1)).add("once"); verify(mockedList, times(2)).add("twice"); verify(mockedList, times(3)).add("three times"); // --------------------------------------------------------- // ....呼び出し回数が想定していた回数以下であるか検証する // --------------------------------------------------------- verify(mockedList, atMost(0)).add("never happened"); verify(mockedList, atMost(1)).add("never happened"); verify(mockedList, atMost(1)).add("once"); verify(mockedList, atMost(2)).add("never happened"); verify(mockedList, atMost(2)).add("once"); verify(mockedList, atMost(2)).add("twice"); verify(mockedList, atMost(3)).add("never happened"); verify(mockedList, atMost(3)).add("once"); verify(mockedList, atMost(3)).add("twice"); verify(mockedList, atMost(3)).add("three times"); // --------------------------------------------------------- // ....呼び出し回数が想定していた回数以上であるか検証する // --------------------------------------------------------- verify(mockedList, atLeast(0)).add("never happened"); verify(mockedList, atLeast(0)).add("once"); verify(mockedList, atLeast(0)).add("twice"); verify(mockedList, atLeast(0)).add("three times"); verify(mockedList, atLeast(1)).add("once"); verify(mockedList, atLeast(1)).add("twice"); verify(mockedList, atLeast(1)).add("three times"); verify(mockedList, atLeast(2)).add("twice"); verify(mockedList, atLeast(2)).add("three times"); verify(mockedList, atLeast(3)).add("three times"); } } **5. Stubbing void methods with exceptions [#b2909624] #highlightjs([java]) package org.codereign.mockito.tutorial.tutorial05; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import java.util.List; import org.junit.jupiter.api.Test; /** * 戻り値を返さないメソッドで例外を発生させる方法 */ public class Tutorial05Test { @SuppressWarnings({ "rawtypes" }) @Test public void test() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- List mockedList = mock(List.class); doThrow(new RuntimeException()).when(mockedList).clear(); // --------------------------------------------------------- // Act & Assert // --------------------------------------------------------- try { mockedList.clear(); fail("RuntimeException が発生する想定のため到達不可能なはず"); } catch (Exception e) { assertTrue(e instanceof RuntimeException); } verify(mockedList).clear(); } } **6. Verification in order [#v258ce19] **7. Making sure interaction(s) never happened on mock [#h804e9a7] #highlightjs([java]) package org.codereign.mockito.tutorial.tutorial07; import static org.mockito.Mockito.*; import java.util.List; import org.junit.Test; /** * モックが未使用であることを検証する方法 */ public class Tutorial07Test { @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void test() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- List mockOne = mock(List.class); List mockTwo = mock(List.class); List mockThree = mock(List.class); // --------------------------------------------------------- // Act // --------------------------------------------------------- mockOne.add("one"); // --------------------------------------------------------- // Assert // --------------------------------------------------------- verify(mockOne).add("one"); verify(mockOne, never()).add("two"); verifyNoInteractions(mockTwo, mockThree); } } **8. Finding redundant invocations [#g99ac47a] **9. Shorthand for mocks creation - @Mock annotation [#qd4363ba] **10. Stubbing consecutive calls (iterator-style stubbing) [#h9de86df] #highlightjs([java]) package org.codereign.mockito.tutorial.tutorial10; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import org.junit.jupiter.api.Test; public class Tutorial10Test { class SomeClass { public String someMethod(String argument) { return null; } } @Test public void test1() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- SomeClass mock = mock(SomeClass.class); when(mock.someMethod("some arg")) .thenReturn("one") .thenReturn("two") .thenReturn("three"); // --------------------------------------------------------- // Act & Assert // --------------------------------------------------------- assertEquals("one", mock.someMethod("some arg")); assertEquals("two", mock.someMethod("some arg")); assertEquals("three", mock.someMethod("some arg")); } @Test public void test2() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- SomeClass mock = mock(SomeClass.class); when(mock.someMethod("some arg")).thenReturn("one", "two", "three"); // --------------------------------------------------------- // Act & Assert // --------------------------------------------------------- assertEquals("one", mock.someMethod("some arg")); assertEquals("two", mock.someMethod("some arg")); assertEquals("three", mock.someMethod("some arg")); } /** * 誤った使い方 */ @Test public void test3() { // --------------------------------------------------------- // Arrange // ....モック化 // --------------------------------------------------------- SomeClass mock = mock(SomeClass.class); when(mock.someMethod("some arg")).thenReturn("one"); when(mock.someMethod("some arg")).thenReturn("two"); when(mock.someMethod("some arg")).thenReturn("three"); // --------------------------------------------------------- // Act & Assert // --------------------------------------------------------- assertEquals("three", mock.someMethod("some arg")); assertEquals("three", mock.someMethod("some arg")); assertEquals("three", mock.someMethod("some arg")); } } **11. Stubbing with callbacks [#kc596313] **12. doReturn()|doThrow()|doAnswer()|doNothing()|doCallRealMethod() family of methods [#ff39fd85] **13. Spying on real objects [#n0df4e14] **14. Changing default return values of unstubbed invocations (Since 1.7) [#ff98ee4f] **15. Capturing arguments for further assertions (Since 1.8.0) [#l66a93c1] **16. Real partial mocks (Since 1.8.0) [#z0ed8bc3] **17. Resetting mocks (Since 1.8.0) [#t4b91a84] **18. Troubleshooting & validating framework usage (Since 1.8.0) [#ia880169] **19. Aliases for behavior driven development (Since 1.8.0) [#wc949689] **20. Serializable mocks (Since 1.8.1) [#v86455a3] **21. New annotations: @Captor, @Spy, @InjectMocks (Since 1.8.3) [#o731935e] **22. Verification with timeout (Since 1.8.5) [#cbbf4797] **23. Automatic instantiation of @Spies, @InjectMocks and constructor injection goodness (Since 1.9.0) [#n2dd8987] **24. One-liner stubs (Since 1.9.0) [#la75b401] **25. Verification ignoring stubs (Since 1.9.0) [#f6d4981a] **26. Mocking details (Improved in 2.2.x) [#a90bf35d] **27. Delegate calls to real instance (Since 1.9.5) [#a5e4b274] **28. MockMaker API (Since 1.9.5) [#d9fa2d81] **29. BDD style verification (Since 1.10.0) [#c22482d7] **30. Spying or mocking abstract classes (Since 1.10.12, further enhanced in 2.7.13 and 2.7.14) [#i95ffaef] **31. Mockito mocks can be serialized / deserialized across classloaders (Since 1.10.0) [#w1fb1771] **32. Better generic support with deep stubs (Since 1.10.0) [#ff90815c] **33. Mockito JUnit rule (Since 1.10.17) [#k983fc98] **34. Switch on or off plugins (Since 1.10.15) [#f0e8a40b] **35. Custom verification failure message (Since 2.1.0) [#g8fdc396] **36. Java 8 Lambda Matcher Support (Since 2.1.0) [#p94972d4] **37. Java 8 Custom Answer Support (Since 2.1.0) [#o37db21d] **38. Meta data and generic type retention (Since 2.1.0) [#ad7352bb] **39. Mocking final types, enums and final methods (Since 2.1.0) [#ha35116b] **40. Improved productivity and cleaner tests with "stricter" Mockito (Since 2.+) [#kf8d7056] **41. Advanced public API for framework integrations (Since 2.10.+) [#i9a38ca7] **42. New API for integrations: listening on verification start events (Since 2.11.+) [#sa48d883] **43. New API for integrations: MockitoSession is usable by testing frameworks (Since 2.15.+) [#t4ef5c1f] **44. Deprecated org.mockito.plugins.InstantiatorProvider as it was leaking internal API. it was replaced by org.mockito.plugins.InstantiatorProvider2 (Since 2.15.4) [#k87bdacd] **45. New JUnit Jupiter (JUnit5+) extension [#w10f43ed] **46. New Mockito.lenient() and MockSettings.lenient() methods (Since 2.20.0) [#odf52209] **47. New API for clearing mock state in inline mocking (Since 2.25.0) [#x1397804] **48. New API for mocking static methods (Since 3.4.0) [#lc9ba15e] **49. New API for mocking object construction (Since 3.5.0) [#a71822a5] *Maven [#sfd41c42] **pom.xml [#k6739059] ***必要最低限 [#n8991aee] #highlightjs([xml]) <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.codereign</groupId> <artifactId>mockito-example</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> <maven.compiler.target>${java.version}</maven.compiler.target> <maven.compiler.source>${java.version}</maven.compiler.source> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency> </dependencies> </project> ***mockito-inline [#p8c4b872] 下記のエラーが発生した場合 ***static method をモック化したい場合 [#p8c4b872] 必要最低限のJARライブラリだと下記のエラーが発生します。 "mockito-inline"を追加してください。 org.mockito.exceptions.base.MockitoException: The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks Mockito's inline mock maker supports static mocks based on the Instrumentation API. You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'. #highlightjs([xml]) <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.codereign</groupId> <artifactId>mockito-example</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> <maven.compiler.target>${java.version}</maven.compiler.target> <maven.compiler.source>${java.version}</maven.compiler.source> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency> </dependencies> </project> *参考サイト [#x6b65631] -"Mockito (Mockito 3.11.2 API)". Mockito framework site.~ [[https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html]], (2021-07-31)