PowerMock integration unit test

Posted by grglaz on Tue, 25 Jan 2022 16:49:06 +0100

catalogue

1, What is Mock?

2, Why use PowerMock?

3, Common notes and methods of PowerMock

4, How to use PowerMock for unit testing?

1, What is Mock?

Mock is to create a mock object to simulate the behavior of some objects that are not easy to construct / obtain during the test. For example, if you need to call the B service, but the B service has not been developed yet, you can give the part of calling the B service to mock and write the return result you want.

Mock has many implementation frameworks, such as Mockito, EasyMock, Jmockit, PowerMock, Spock, etc. the default mock framework of SpringBoot is Mockito. Like junit, it only needs to rely on spring boot starter test.

2, Why use PowerMock?

Mockito framework does not support static # and mock of non-public methods or member variables. PowerMock extends EasyMock and mockito framework, adds the functions of mock static and Final methods, and realizes the simulation support of static methods, construction methods, private methods and Final methods.

3, Common notes and methods of PowerMock

  • @Runwith(PowerMockRunner.class): Specifies the runner. To use powermock, you need to configure it. Otherwise, powermock cannot be used.
  • @PrepareForTest({Util.class}): when you need to use the powerful functions of PowerMock (mock static, final, private methods, etc.), you need to annotate @ PrepareForTest annotation, util Class is the class of the static method that needs mock.
  • @MockBean: create a mock object and add the mock object to the Spring context using the @ MockBean annotation.
  • @AutoConfigureMockMvc: automatically configure mockmvc, which can be used to simulate HTTP requests.
  • @AutoConfigureWebTestClient: AutoConfigureWebTestClient, like mockMvc, is used to simulate HTTP requests.
  • @Mock: all calls to functions execute mock (i.e. false functions) and do not execute the real part.
  • @Spy: calls to functions execute the real part.
  • @InjectMocks: create an instance. In short, this Mock can call the methods of real code, and the other mocks created with @ Mock (or @ Spy) annotation will be injected into the instance.

4, How to use PowerMock for unit testing?

1. Introduce dependency

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.28.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>

2. Write BaseTest base class

// The rollback of configuration transaction and the addition, deletion and modification of database will be rolled back to facilitate the recycling of test cases
@Rollback
@Transactional
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "com.rabbitmq.*", "org.apache.log4j.*"})
@SpringBootTest
public abstract class BaseTest {
}

3. Basic usage of PowerMock

1) mock Http request

1,use MockMvc simulation Http request	  
@AutoConfigureMockMvc
public class DemoTest extends BaseTest {
 	  @Test
    void addUser() {
        User user = new User(1, "alien", "man", 12);
   
        try {
            mockMvc.perform(MockMvcRequestBuilders.post("/user/save")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(JSONObject.toJSONString(user)))
                    // Declare expected response results
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    // Print response results
                    .andDo(MockMvcResultHandlers.print());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
    
    
2,use WebTestClient simulation Http request	
@AutoConfigureWebTestClient
public class DemoTest extends BaseTest {
  	@Test
    void findUserById() {
        User user = webClient.get()
                // Declare the request interface address, request parameters, request data flow type and request header
                .uri(uriBuilder -> uriBuilder.path("/user/id")
                .queryParam("id", 2).build())
                .accept(MediaType.APPLICATION_JSON)
                .header("token", "123456")
                // Execute request
                .exchange()
                // Declare response status and header
                .expectStatus().isOk()
                .expectHeader().contentType(MediaType.APPLICATION_JSON)
                // Specifies how the response body is decoded and used
                .expectBody(User.class)
                // Obtain corresponding results
                .returnResult()
                .getResponseBody();
        System.out.println(user.toString());               
    }
}
   

2. mock common method

Test object code:

@Component
public class StudentService {

    @Autowired
    private StudentDao studentDao;

    public String findStudents() {
        return studentDao.findStudents();
    }

}


@Component
public class StudentDao {

    public String findStudents() {
        return "i am dao data";
    }

}

Test case code:

public class DemoTest extends BaseTest {
  	@MockBean
    private StudentDao studentDao;
    
    @Autowired
    private StudentService studentService;
    
    @Test
    public void test() {
        // mock | piling
        when(studentDao.findStudents()).thenReturn("i am mock data");
        Assert.assertEquals("i am mock data", studentDao.findStudents());

        // implement
        String s = studentService.findStudents();
        
        // Use assertions to verify that the returned result is consistent with the expected value of mock
        Assert.assertEquals("i am mock data", s);
    }
}

3. mock static method

Test object code:

@Component
public class UserService {

    public String userStaticMethod() {
        String name = UserUtil.getName();
        return name;
    }

}


public class UserUtil {
    public static String getName() {
        return "static-method: Bob";
    }
}

Test case code:

@PrepareForTest({UserUtil.class})
public class DemoTest extends BaseTest {    
    @Autowired
    private UserService userService;
    
    @Test
    public void test() {
        // Pile driving
        PowerMockito.mockStatic(UserUtil.class);
        when(UserUtil.getName()).thenReturn("i am changed!");

        // implement
        String s = userService.userStaticMethod();
        
        // Use assertions to verify that the returned result is consistent with the expected value of mock
        Assert.assertEquals("i am changed!", s);
    }
}

4. mock private method

Test object code:

@Component
public class UserService {

    public String userPrivateMethod(String name) {
        return privateMethod(name);
    }

    private String privateMethod(String name) {
        return name;
    }

}

Test case code:

PowerMockito.spy(): create simulated objects. If mock rules are not set, real methods will be executed. If mock rules are set, false methods will be executed.

PowerMockito.mock()/@MockBean: mock() or mock objects created by @ MockBean will always execute false methods. If mock rules are set, the false methods will return the expected value. If mock rules are not set, the methods will directly return null

@PrepareForTest({UserUtil.class,UserService.class})
public class DemoTest extends BaseTest {
    
    @Test
    public void test() {
        // Pile driving
        UserService spy = PowerMockito.spy(new UserService());
        try {
            PowerMockito.when(spy, "privateMethod", anyString()).thenReturn("private method changed!!!");
        } catch (Exception e) {
            e.printStackTrace();
        }

        // implement
        String s = spy.userPrivateMethod("test");
        
        // Use assertions to verify that the returned result is consistent with the expected value of mock
        Assert.assertEquals("private method changed!!!", s);
    }
}

Topics: Java Spring unit testing