Spring boot unit testing tool Mockito

Mockito is a Java mock framework. It is mainly used for mock testing. It can simulate any Spring managed bean, the return value of the simulated method, and the exception thrown. Before understanding the specific usage of mockito, you need to know what is mockito testing

1. What is mock test?

mock testing is to create a fake object during the testing process, so as to avoid that you have to build the whole bean dependency chain to test a method

As shown in the following figure, class A needs to call class B and class C, while class B and class C need to call other classes, such as D, E, F, etc. assuming that class D is an external service, it will be difficult to test, because your return results will be directly affected by the external service, which may lead to your unit test passing today, but not tomorrow

When we introduce the mock test, we can create A fake object and replace the real beans B and C, so that when we call the methods of B and C, we will actually call the methods of the fake mock object, and we can set the parameters and expected results of the mock object ourselves, so that we can focus on testing the current class A without being affected by other methods External service impact, so the test efficiency can be improved A lot

2. Introduction to mockito

Now that we're done with the concept of mock testing, let's move on to today's topic, Mockito

Mockito is a Java mock framework, which is mainly used for mock testing. It can simulate any Spring managed bean, the return value of the simulation method, the exception thrown by the simulation, etc. at the same time, it will also record the parameters and the calling order of these simulation methods, so as to check whether the mock object is called in the correct order and according to the expected order Parameter called

For example, Mockito can simulate the data returned by a service in unit test without actually calling the service. This is the above-mentioned mocking test spirit, that is, by simulating a fake service object, to quickly test the current class I want to test

At present, the mainstream mock testing tools in Java include Mockito, JMock, EasyMock... And so on. Spring boot currently builds the Mockito framework

As an aside, Mockito is named after a kind of Mojito. Foreigners also like to play homophonic stem...

3. Using Mockito in spring boot unit test

First, add a spring boot starter test dependency under pom.xml, which includes JUnit and Mockito

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

First, write a UserService. There are two methods in it: getUserById() and insertUser(). They will call the getUserById() and insertUser() methods of UserDao

@Component
public class UserService {
    
    @Autowired
    private UserDao userDao;

    public User getUserById(Integer id) {
        return userDao.getUserById(id);
    }

    public Integer insertUser(User user) {
        return userDao.insertUser(user);
    }
}

The User model is defined as follows

public class User {
    private Integer id;
    private String name;
    //Omit getter/setter
}

If we do not use Mockito to simulate a fake userDao bean at this time, but really call the userDao of a normal Spring bean, the test class is written as follows. In fact, it is very common to inject the userService bean, then call his method, and he will call userDao to get the data of the database, and then we will make assert check on the returned result

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {

    //First, inject a userService bean
    @Autowired
    private UserService userService;

    @Test
    public void getUserById() throws Exception {
        //If you use userService, you will call userDao to get the data of the database
        User user = userService.getUserById(1);
        
        //Examination result
        Assert.assertNotNull(user);
        Assert.assertEquals(user.getId(), new Integer(1));
        Assert.assertEquals(user.getName(), "John");
    }
}

But if the user Dao hasn't been written and wants to test the user service first, you need to use Mockito to simulate a fake user Dao

The way to use it is to add a @ mock bean annotation to userDao. When userDao is added with this annotation, it means that Mockito will help us create a fake mock object and replace the existing real userDao bean in Spring, that is to say, the userDao bean injected into userService has been replaced by the fake mock object. So when we When calling the userService method again, it will actually call the method of the mock userDao bean instead of the real userDao bean

When we create a fake userDao, we need to customize the return value of the method for the mock userDao. Here is a formula usage. The following code means that when a method of a mock object is called, the user-defined result we want will be returned

Mockito. When (object. Method name ()). Thenreturn (custom result)

An example of unit testing using Mockito to simulate bean s is as follows

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @MockBean
    private UserDao userDao;

    @Test
    public void getUserById() throws Exception {
        // Defines that when the getUserById() method of the mock userDao is called and the parameter is 3, the user object with id 200 and name I'm mock3 is returned
        Mockito.when(userDao.getUserById(3)).thenReturn(new User(200, "I'm mock 3"));
        
        // It will return a user object named I'm mock 3
        User user = userService.getUserById(1);

        Assert.assertNotNull(user);
        Assert.assertEquals(user.getId(), new Integer(200));
        Assert.assertEquals(user.getName(), "I'm mock 3");
    }
}

In addition to the basic "Mockito. When" (object. Method name ()). Thenreturn (custom result), Mockito also provides other uses for us to use

thenReturn series methods

When the getUserById() method of userService is called with any integer value, a user object named I'm mock3 is returned

Mockito.when(userService.getUserById(Mockito.anyInt())).thenReturn(new User(3, "I'm mock"));
User user1 = userService.getUserById(3); // The name of the returned user is I'm mock
User user2 = userService.getUserById(200); // The returned user's name is also I'm mock

Limit the return of user object named I'm mock 3 only when the number of parameter is 3

Mockito.when(userService.getUserById(3)).thenReturn(new User(3, "I'm mock"));
User user1 = userService.getUserById(3); // The name of the returned user is I'm mock
User user2 = userService.getUserById(200); // The returned user is null

When the insertUser() method of userService is called, it returns 100 regardless of the user passed in

Mockito.when(userService.insertUser(Mockito.any(User.class))).thenReturn(100);
Integer i = userService.insertUser(new User()); //Will return to 100

thenThrow series methods

When the parameter of getUserById() of userService is 9, a RuntimeException is thrown

Mockito.when(userService.getUserById(9)).thenThrow(new RuntimeException("mock throw exception"));
User user = userService.getUserById(9); //A RuntimeException will be thrown

If the method does not return a value (that is, the method is defined as public void myMethod() {...}), use doThrow() instead to throw an Exception

Mockito.doThrow(new RuntimeException("mock throw exception")).when(userService).print();
userService.print(); //A RuntimeException will be thrown

verify series method

Check if the number of times to call getUserById() of userService with parameter 3 is 1

Mockito.verify(userService, Mockito.times(1)).getUserById(Mockito.eq(3)) ;

Verify the calling order, and verify whether the userService calls getUserById() twice, and the first parameter is 3, and the second parameter is 5, then the insertUser() method is called

InOrder inOrder = Mockito.inOrder(userService);
inOrder.verify(userService).getUserById(3);
inOrder.verify(userService).getUserById(5);
inOrder.verify(userService).insertUser(Mockito.any(User.class));

4. Limitation of mockito

The above is the usage of Mockito's mockobject, but when using Mockito in a mockobject, there are some limitations that need to be observed

  • Cannot mock static methods

  • Cannot mock private method

  • Can't mock final class

Therefore, when writing code, we need to do a good function splitting to use Mockito's mock technology to help us reduce the coupling of bean s during testing

5. summary

Mockito is a very powerful framework, which can help us simulate a bean when executing unit tests and improve the stability of unit tests

In addition, you can try to write code from the perspective of mock test, and you can write a code architecture with good function segmentation. For example, if you extract the code specially used to communicate with external services into a bean, you can replace the bean through Mockito during unit test

656 original articles published, 331 praised, 310000 visitors+
His message board follow

Tags: Spring Java Database xml

Posted on Sat, 08 Feb 2020 06:16:21 -0500 by stevietee