Unit Test Series: Mockito Actual Combat of Mock Tool

Mock tool overview

1.1 Introduction to Mockito

 

Both EasyMock and Mockito are used by many people in their work because they can greatly simplify the writing process of unit tests, but neither of these two Mock tools can implement static functions, constructors, private functions, Final functions, and system functions. , but these methods are often the functions we need in large systems.

In addition, for more new features of Mockito2.0, refer to the official introduction document, which contains the reasons for not mocking private, which is quite interesting:

https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2

1.2 Mockito preparations

###Maven###

Managed by Maven, you need to add the following dependencies to the project's Pom.xml:

copy code

 <dependencies>

<dependency>

<groupId>org.mockito</groupId>

<artifactId>mockito-core</artifactId>

<version>2.7.19</version>

<scope>test</scope>

</dependency>

</dependencies>

copy code

 

 

You can import org.mockito.Mockito in the program, and then call its static method.

Maven users can declare a dependency on mockito-core. Mockito is automatically published to Bintray Central and synced to Maven Central Repository.

Special reminder: Legacy builds with manual dependency management can use the 1.* "mockito-all" distribution. It can be downloaded from Mockito's Bintray repository or from Bintray's hub. In Mockito 2. * "mockito-all" distribution has been discontinued, Mockito 2 and above use "mockito-core".

Official website download center:

http://search.maven.org/#search|gav|1|g%3A%22org.mockito%22%20AND%20a%3A%22mockito-core%22

The latest version is currently 2.7.19. Due to the problem of the company's network gateway, it is best to download it manually from the official website.

In addition, Mockito needs to be used in conjunction with Junit, which is also introduced in the Pom file:

copy code

<dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
      </dependency>

copy code

Then, in order to make the code more concise, it is best to import static resources in the test class, and in order to use the commonly used junit keywords, also introduce two junit classes Before and Test:

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

1.3 Simulation objects

The syntax for creating a Mock object is mock(class or interface).

Creation of mock objects

mock(Class classToMock);
 mock(Class classToMock, String name)
 mock(Class classToMock, Answer defaultAnswer)
 mock(Class classToMock, MockSettings mockSettings)
 mock(Class classToMock, ReturnValues returnValues)

You can create mock objects for classes and interfaces, and you can name the mock objects when creating them. The advantage of naming the mock object is that it is easy to identify the mock object when debugging.

 

Expected behavior and return value setting of Mock object

Suppose we create a mock object of the LinkedList class:

 LinkedList mockedList = mock(LinkedList.class);

1.4 Set the expected return value of the object call

Use when(mock.someMethod()).thenReturn(value) to set the return value when a method of the Mock object is called. We can look at the comments on the thenReturn method in the source code:

 

Use when(mock.someMethod()).thenThrow(new RuntimeException) to set the exception thrown when a method is called.

 

and Answer:

 

 

Answer is a generic interface. This callback will be executed when the call occurs, and the parameters passed in during the call can be obtained through Object[] args = invocation.getArguments();, and the mock object can be obtained through Object mock = invocation.getMock();

Some methods may have an interface parameter of a Listener parameter. If we use Answer piling, we can get this Listener and execute the corresponding callback function in the Answer function, which is very helpful for us to understand the internal execution of the function. .

Use doThrow(new RuntimeException("clear exception")).when(mockedList).clear();mockedList.clear(); Mock does not have a return value type function:

doThrow(new RuntimeException()).when(mockedList).clear();

// will throw a RuntimeException:

mockedList.clear();

This example indicates that when mockedList.clear() is executed, a RuntimeException will be thrown. Other doXXX implementations are similar to it.

For example: doReturn()|doThrow()| doAnswer()|doNothing()|doCallRealMethod() series of methods.

 

Spy function:

You can create a spy object for the real object, and when you use this spy object, the real object will also be called, unless its functions are stubbed. You should use spy objects as little as possible, and you need to be careful when using them. For example, spy objects can be used to deal with legacy code. Spy examples are as follows:

copy code

List list = new LinkedList();

//监控一个真实对象

List spy = spy(list);

//你可以为某些函数打桩

when(spy.size()).thenReturn(100);

//使用这个将调用真实对象的函数

spy.add("one");

spy.add("two");

//打印"one"

System.out.println(spy.get(0));

//size() 将打印100

System.out.println(spy.size());

//交互验证

verify(spy).add("one"); 
verify(spy).add("two");

copy code

It is very important to understand that monitoring real objects, sometimes it is impossible or impractical to stub using when(Object) on the monitoring object. Because, when using monitoring objects, please consider using doReturn, Answer, Throw () function group for piling, for example:

List list = new LinkedList();

List spy = spy(list);

//This is impossible: because calling spy.get(0) will call the get(0) function of the real object, this will happen

//IndexOutOfBoundsException because the real object is empty when(spy.get(0)).thenReturn("foo");

//You need to use doReturn() to pile

doReturn("foo").when(spy).get(0);

Mockito does not proxy function calls for the real object, it actually copies the real object, so if you keep the real object and interact with it, don't expect the mocked object to get the correct result. When you call a non-stub function on the monitor object, the corresponding function on the real object will not be called, and you will not see any effect on the real object.

1.5 Verify the class method under test

Once the Mock object is created, it will automatically record its own interaction behavior, so we can selectively verify its interaction behavior. The method to verify the interactive behavior of Mock objects in Mockito is verify(mock).someMethod(…). Finally Assert() verifies that the return value is as expected.

1.6 Demo

 I found one of the simplest code examples from the Internet. The following is a specific code to demonstrate how to use Mockito. There are three types of code, which are as follows:

Person class:

copy code

public class Person {
    private final int id; 
    private final String name; 
    public Person(int id, String name) { 
        this.id = id; 
        this.name = name; 
        } 
    public int getId() { 
        return id; 
        } 
    public String getName() { 
        return name; 
        }
}

copy code

PersonDao class:

public interface PersonDao {
    Person getPerson(int id); 
    boolean update(Person person); 
    }

PersonService class:

 

copy code

public class PersonService {
    private final PersonDao personDao; 
    public PersonService(PersonDao personDao) { 
        this.personDao = personDao; 
        } 
    public boolean update(int id, String name) { 
        Person person = personDao.getPerson(id); 
        if (person == null) 
        { return false; } 
        Person personUpdate = new Person(person.getId(), name); 
        return personDao.update(personUpdate); 
        }
}

copy code

 

Still use Junit to automatically generate test classes or create new test classes manually:

 

 

After the test code is generated, delete the default assertfail and enter the following two test methods:

copy code

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;


public class PersonServiceTest {

    private PersonDao     mockDao;
    private PersonService personService;

    @Before
    public void setUp() throws Exception {
        //模拟PersonDao对象
        mockDao = mock(PersonDao.class);
        when(mockDao.getPerson(1)).thenReturn(new Person(1, "Person1"));
        when(mockDao.update(isA(Person.class))).thenReturn(true);

        personService = new PersonService(mockDao);
    }

    @Test
    public void testUpdate() throws Exception {
        boolean result = personService.update(1, "new name");
        assertTrue("must true", result);
        //验证是否执行过一次getPerson(1)
        verify(mockDao, times(1)).getPerson(eq(1));
        //验证是否执行过一次update
        verify(mockDao, times(1)).update(isA(Person.class));
    }

    @Test
    public void testUpdateNotFind() throws Exception {
        boolean result = personService.update(2, "new name");
        assertFalse("must true", result);
        //验证是否执行过一次getPerson(1)
        verify(mockDao, times(1)).getPerson(eq(1));
        //验证是否执行过一次update
        verify(mockDao, never()).update(isA(Person.class));
    }
}

copy code

Note: We mock PersonDAO and set stubbing. The stubbing settings are as follows:

  • When the getPerson method passes in 1, it returns a Person object, otherwise it returns empty by default
  • When the update method is called, return true

Here two parameter matchers are used:

  isA():Object argument that implements the given class.

  eq():int argument that is equal to the given value

Note: Mockito uses verify to verify whether the method is called, and then uses the built-in parameter matchers such as isA and eq to be more flexible.

For detailed use of parameter matchers, please refer to the official website documentation: https://static.javadoc.io/org.mockito/mockito-core/2.25.0/org/mockito/ArgumentMatchers.html

Since the code and explanations on the official website are very detailed, I won't repeat them here.

 

Still call Junit to execute the unit test code, the result is as shown in the figure:

Two cases are verified:

  • Update the name of the Person whose id is 1. It is expected that the Person can be found in DAO and the update is successful
  • Update the name of Person with id 2, expected: Cannot find Person in DAO, update failed

Here you can also view the exception information thrown by Eclipse:

Argument(s) are different! Wanted:

personDao.getPerson(1);

-> at PersonServiceTest.testUpdateNotFind(PersonServiceTest.java:41)

Actual invocation has different arguments:

personDao.getPerson(2);

-> at PersonService.update(PersonService.java:8)

2 Unit testing and coverage

1、Junit 2、JaCoCo 3、EclEmma

2 coverage

The coverage rate is shown in the figure below:

Coverage still uses JaCoCo and EclEmma:

l Uncovered code is marked in red

l Covered code will be marked in green

l Partially covered code is marked in yellow

Colors can also be customized in Eclipse:

In the status bar window below Eclipse, there is a column "Coverage", click to display detailed code coverage:

How to export as Report in Html format:

Right-click on the Coverage column under Eclipse and select "Export Session...", and select the export target as "Coverage Report" in the pop-up window, as shown below:

After clicking the "Next" button, select the session and Format to be exported in the next pop-up window

Select "HTML report" as the type, temporarily select the desktop as the export location, and click the "Finish" button after all selections to generate it.

Find a page called index.html on the desktop that is the newly generated Coverage Report:

Click the folder to enter the directory, and further view the coverage of sub-files:

 

mockito mock static method

  • Blog Category: 
  • test

 


Notes  on using powerMock  :
1 @RunWith(PowerMockRunner.class) 
2 PowerMockito.mockStatic(StaticTest.class); 

Java code 

 favorite code

  1. package com.eyu.ahxy.module.staticd;  
  2.   
  3. import static org.hamcrest.Matchers.equalTo;  
  4. import static org.junit.Assert.assertThat;  
  5.   
  6. import org.junit.Test;  
  7. import org.junit.runner.RunWith;  
  8. import org.powermock.api.mockito.PowerMockito;  
  9. import org.powermock.modules.junit4.PowerMockRunner;  
  10.   
  11. @RunWith(PowerMockRunner.class)  
  12. public class StaticTest {  
  13.   
  14.     @Test  
  15.     public void test1() {  
  16.         PowerMockito.mockStatic(StaticTest.class);  
  17.         PowerMockito.when(StaticTest.static1()).thenReturn("static");  
  18.         String result = StaticTest.static1();  
  19.         assertThat(result, equalTo("static"));  
  20.     }  
  21.   
  22.     public static String static1() {  
  23.         return "test1";  
  24.     }  
  25.   
  26. }  



powmock的maven依赖: 

<dependency> 
<groupId>org.powermock</groupId> 
<artifactId>powermock-api-mockito</artifactId> 
<version>1.6.1</version> 
<scope>test</scope> 
</dependency> 

<dependency> 
<groupId>org.powermock</groupId> 
<artifactId>powermock-module-junit4</artifactId> 
<version>1.6.1</version> 
<scope>test</scope> 
</dependency>

Guess you like

Origin blog.csdn.net/weixin_36667844/article/details/89944760