This is the 12th day of my participation in Gwen Challenge

Mockito is a Unit test simulation framework for Java. Similar to EasyMock and jMock, Mockito is a tool developed to simplify the construction of test contexts (also known as test drivers and stub functions) during unit testing

The advantage of Mockito over EasyMock and jMock is that it eliminates the need for expectations by verifying which functions have been called after execution. Other mocking libraries require recording expectations before execution, which tends to result in ugly initialization code.

The following dependencies need to be added to the pom.xml file in SpringBoot:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
Copy the code

If you go to spring-boot-starter-test-2.1.3.release.pom, you can see that this dependency already has most of the dependencies required for unit testing, such as:

Junit Mockito Hamcrest For other Spring projects, you need to add junit and Mockito projects yourself.

Common Mockito methods:

The method name describe
Mockito.mock(classToMock) The mock object
Mockito.verify(mock) Verify that the behavior occurred
Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) When triggered, value1 is returned for the first time and Value2 is returned for the NTH time
Mockito.doThrow(toBeThrown).when(mock).[method] Simulate throwing an exception.
Mockito.mock(classToMock,defaultAnswer) Use the default Answer mock object
Mockito.when(methodCall).thenReturn(value) The parameter match
Mockito.doReturn(toBeReturned).when(mock).[method] Parameter matching (execute directly without judgment)
Mockito.when(methodCall).thenAnswer(answer)) Expected callback interface generates expected values
Mockito.doAnswer(answer).when(methodCall).[method] Expected callback interface generation expectation (execute directly without judgment)
Mockito.spy(Object) Use SPY to monitor real objects and set real object behavior
Mockito.doNothing().when(mock).[method] Do nothing back
Mockito.docallrealmethod ().when(mock).[method] // equivalent to mockito.when (mock.[method]).thencallRealMethod (); Call the real method
reset(mock) Reset the mock

Example: Verify that the behavior occurred

List<Integer> mock = mockito.mock (list.class); Mock.add (1); // Call the mock object method mock.add(1); mock.clear(); // Verify whether the method executes mockito.verify (mock).add(1); Mockito.verify(mock).clear();Copy the code

Multiple triggers return different values

Iterator Iterator = mock(iterator.class); When (iterator.next()).thenreturn ("hello").thenreturn ("world"); String result = iterator.next() + "" + iterator.next() +" "+ iterator.next(); AssertEquals (" Hello world",result); // Assert.assertequals (" Hello world",result);Copy the code

Simulating throwing an exception

@test (expected = ioException.class)// Expected I/O exception public void when_thenThrow() throws IOException{OutputStream mock = Mockito.mock(OutputStream.class); Mockito.dothrow (new IOException()).when(mock).close(); mock.close(); }Copy the code

Using the default Answer mock object RETURNS_DEEP_STUBS is one of the alternative arguments when creating mock objects. The following methods deepstubsTest and deepstubsTest2 are equivalent

@Test public void deepstubsTest(){ A a=Mockito.mock(A.class,Mockito.RETURNS_DEEP_STUBS); Mockito.when(a.getB().getName()).thenReturn("Beijing"); Assert.assertEquals("Beijing",a.getB().getName()); } @Test public void deepstubsTest2(){ A a=Mockito.mock(A.class); B b=Mockito.mock(B.class); Mockito.when(a.getB()).thenReturn(b); Mockito.when(b.getName()).thenReturn("Beijing"); Assert.assertEquals("Beijing",a.getB().getName()); } class A{ private B b; public B getB(){ return b; } public void setB(B b){ this.b=b; } } class B{ private String name; public String getName(){ return name; } public void setName(String name){ this.name = name; } public String getSex(Integer sex){ if(sex==1){ return "man"; }else{ return "woman"; }}}Copy the code

The parameter match

@Test public void with_arguments(){ B b = Mockito.mock(B.class); Mockito.when(b.getsex (1)).thenreturn (" male "); mockito.when (b.getsex (1)).thenreturn (" male "); Mockito. When (b.g etSex (2)). ThenReturn (" female "); Assert. AssertEquals (" male ", b.g etSex (1)); Assert. AssertEquals (" female ", b.g etSex (2)); AssertEquals (null, b.getsex (0)); } class B{ private String name; public String getName(){ return name; } public void setName(String name){ this.name = name; } public String getSex(Integer sex){ if(sex==1){ return "man"; }else{ return "woman"; }}}Copy the code

Matches any parameter mockito.anyint () with anyInt value; Mockito.anylong () anyLong value; Mockito.anystring () anyString value;

Mockito.any(xxx.class) any values of type XXX and so on.

@Test public void with_unspecified_arguments(){ List list = Mockito.mock(List.class); // Match any argument mockito.when (list.get(mockito.anyint ())).thenReturn(1); Mockito.when(list.contains(Mockito.argThat(new IsValid()))).thenReturn(true); Assert.assertEquals(1,list.get(1)); Assert.assertEquals(1,list.get(999)); Assert.assertTrue(list.contains(1)); Assert.assertTrue(! list.contains(3)); } class IsValid extends ArgumentMatcher<List>{ @Override public boolean matches(Object obj) { return obj.equals(1) || obj.equals(2); }}Copy the code

Note: if parameter matching is used, then all parameters must be matched by matchers Mockito inherited matchers, anyInt(), etc are all matchers method when passing two parameters, one of which takes an arbitrary parameter, the specified parameter needs matchers to compare

Comparator comparator = mock(Comparator.class); comparator.compare("nihao","hello"); Mockito.verify(comparator).compare(mockito.anystring (), mockito.eq ("hello")); Compare (anyString(),"hello"); compare(anyString(),"hello");Copy the code

User-defined parameter matching

@test public void argumentMatchersTest(){// Create a mock object List<String> mock = mock(list.class); The argThat(Matches<T> matcher) method is used to apply custom rules and can be passed in any implementation class that implements the matcher interface. Mockito.when(mock.addAll(Mockito.argThat(new IsListofTwoElements()))).thenReturn(true); Assert.assertTrue(mock.addAll(Arrays.asList("one","two","three"))); } class IsListofTwoElements extends ArgumentMatcher<List> { public boolean matches(Object list) { return((List)list).size()==3; }}Copy the code

Expected callback interface generates expected values

@Test public void answerTest(){ List mockList = Mockito.mock(List.class); Mockito.when(mockList.get(mockito.anyint ())).thenanswer (new CustomAnswer()); Assert.assertEquals("hello world:0",mockList.get(0)); Assert.assertEquals("hello world:999",mockList.get(999)); } private class CustomAnswer implements Answer<String> { @Override public String answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); return "hello world:"+args[0]; }} is equivalent to: (You can also use an anonymous inner class.) @test public void answer_With_callback (){// Use Answer to generate the return we expect Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); return "hello world:"+args[0]; }}); Assert.assertEquals("hello world:0",mockList.get(0)); Assert. assertEquals("hello world:999",mockList.get(999)); }Copy the code

Expected callback interface generation expectations (direct execution)

@Test public void testAnswer1(){ List<String> mock = Mockito.mock(List.class); Mockito.doAnswer(new CustomAnswer()).when(mock).get(Mockito.anyInt()); Assert.assertequals (" greater than three ", mock. Get (4)); assert.assertequals (" greater than three ", mock. Assert.assertequals (" less than three ", mock. Get (2)); assert.assertequals (" less than three ", mock. } public class CustomAnswer implements Answer<String> { public String answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); Integer num = (Integer)args[0]; If (num>3){return ">3 "; } else {return "less than three "; }}}Copy the code

Modify return default expectations for unpreset calls (specify return values)

List mock = mockito.mock (list.class,new Answer() {@override public Object answer(InvocationOnMock invocation) throws Throwable { return 999; }}); // The following get(1) is not preset and normally returns NULL, but uses Answer to change the default expected value assert.assertequals (999, mock.get(1)); // The following size() is not preset and will normally return 0, but using Answer changes the default expected value assert.assertequals (999,mock.size());Copy the code

Use SPY to monitor real objects and set real object behavior

@Test(expected = IndexOutOfBoundsException.class) public void spy_on_real_objects(){ List list = new LinkedList(); List spy = Mockito.spy(list); When (spy.get(0)).thenreturn (3); //Mockito.when(spy.get(0)). Mockito.doreturn (999).when(spy).get(999); // Use doreturn-when to avoid when-thenReturn calling the real object API mockito.doreturn (999). Mockito.when(spy.size()).thenreturn (100); // Call the real object's API spy.add(1); spy.add(2); Assert.assertEquals(100,spy.size()); Assert.assertEquals(1,spy.get(0)); Assert.assertEquals(2,spy.get(1)); Assert.assertEquals(999,spy.get(999)); }Copy the code

Do nothing back

@Test public void Test() { A a = Mockito.mock(A.class); //void method can call doNothing() mockito.donothing ().when(a).setName(mockito.anystring ()); a.setName("bb"); Assert.assertEquals("bb",a.getName()); } class A { private String name; private void setName(String name){ this.name = name; } private String getName(){ return name; }}Copy the code

Call the real method

@Test public void Test() { A a = Mockito.mock(A.class); //void method can call doNothing() mockito.when (a.goetName ()).thenreturn ("bb"); Assert.assertEquals("bb",a.getName()); Mockito.when(a.getName()).thencallRealMethod (); mockito.when (a.getName()).thencallRealMethod (); Mockito.doCallRealMethod().when(a).getName(); Assert.assertEquals("zhangsan",a.getName()); } class A { public String getName(){ return "zhangsan"; }}Copy the code

Reset the mock

@Test public void reset_mock(){ List list = mock(List.class); Mockito. when(list.size()).thenReturn(10); list.add(1); Assert.assertEquals(10,list.size()); // Reset mock to clear all interactions and presets mockito.reset (list); Assert.assertEquals(0,list.size()); }Copy the code

@ Mock annotations

public class MockitoTest { @Mock private List mockList; / / must be added in the base class to initialize the mock code, otherwise an error of the mock object is NULL public MockitoTest () {MockitoAnnotations. InitMocks (this); } @Test public void AnnoTest() { mockList.add(1); Mockito.verify(mockList).add(1); }}Copy the code

Use @MockBean to resolve some dependency issues in unit tests, as shown in the following example:

@RunWith(SpringRunner.class) @SpringBootTest public class ServiceWithMockBeanTest { @MockBean SampleDependencyA dependencyA; @Autowired SampleService sampleService; @Test public void testDependency() { when(dependencyA.getExternalValue(anyString())).thenReturn("mock val: A"); assertEquals("mock val: A", sampleService.foo()); }}Copy the code

MockBean can only mock native code — or self-written code, not classes stored in a library and assembled into code as beans.

@SpyBean addresses the limitations of @MockBean in SpringBoot unit testing that it cannot mock beans that are automatically assembled in the mock library.