How to use Mockito to call static methods and void methods

  • 2021-10-25 06:51:50
  • OfStack

1. mock static method

The mockito library is not an mock static method and relies on powermock

Step 1: Add annotations to classes


//  Static classes are loaded first, so you need to tell them in advance powermock Which static classes require mock
@ContextConfiguration
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@PrepareForTest( Static calling class .class)
public class SupplierServiceImplTest extends PowerMockTestCase {}

Step 2: Using mock


@Test(expectedExceptions = BusinessException.class)
public void testAddSupplierAccount_genIdentityNoError() {
    //  Tell powermock , need mock All static methods of the class 
 PowerMockito.mockStatic(PasswordGenerator.class);
 
 final SupplierAccountDto supplierAccountDto = new SupplierAccountDto();
 supplierAccountDto.setName(" Xiao Ming ");
 final String randomPWd = "666"; 
 PowerMockito.when(supplierDao.selectByEmail(anyString()))
   .thenReturn(new ArrayList<HaitaoSupplier>());
 //  Static method mock
 PowerMockito.when(PasswordGenerator.genPwd()).thenReturn(randomPWd);
 PowerMockito.when(pwEncoder.encode(anyString())).thenReturn(randomPWd);
 PowerMockito.when(identityNoGenerator.genIdentityNo()).thenReturn(-1L);
 
 supplierServiceImpl.addSupplierAccount(supplierAccountDto); 
 verify(pwEncoder).encode(randomPWd);
}

2. mock void method


// void Well, doNothing As the name implies 
PowerMockito.doNothing().when(casService).addSupplier(anyLong(), any(ServiceKey.class));

Use PowerMockito and Mockito for simulation test

Include static method testing, private method testing, etc., and method execution pits or simulation unsuccessful resolution

1 General spring Project

Dependence: This is very important, and the usage of different versions is also somewhat different:


<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>2.0.2-beta</version>
    <scope>test</scope>
</dependency>
 
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>1.7.4</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>
 
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-core</artifactId>
    <version>1.7.4</version>
    <scope>test</scope>
</dependency>

Next is the mock test, which uses the complete simulation test process to return the expected results you want for the static and private methods that need to be called in the test interface to achieve the test effect:

Here are a few key points:

During the test, mock was completely manual, and no real call or data was generated

1 mock Object

order = mock(Order.class);
user = mock(User.class);
2 attribute injection

The other service, such as service or mapper, needed in the service and other mock, and then use the tool class injection respectively, and keep the name 1


roomTypeService = mock(RoomTypeServiceImpl.class);
ticketComponetService = mock(TicketComponetServiceImpl.class);
hotelMapper = mock(HotelMapper.class);
// Injection attribute 
ReflectionTestUtils.setField(orderService, "hotelGroupMapper", hotelGroupMapper);
ReflectionTestUtils.setField(orderService, "dsUtils", dsUtils);
ReflectionTestUtils.setField(orderService, "orderMapper", orderMapper);
3 Static method mock

PowerMockit is required to simulate the results returned by static methods, and the test class must be annotated @ PrepareForTest


//account  Get stub
PowerMockito.mockStatic(Account.class);
Mockito.when(Account.get(anyString(), anyString(), anyString(), anyInt())).thenReturn(account);
4 Private methods

Private methods need to be annotated on the class first, which is also effective for public methods in the class to be tested. For example, if the test method contains one public method, it can be simulated as well:


@PrepareForTest(ConsumptionServiceImpl.class)  // It writes classes that need to simulate private methods class

Then the object cannot be mock, it must have new1, and it needs to be processed with spy:


orderService = PowerMockito.spy(new OrderServiceImpl());

Then use the formal mode of doreturn. when, but you can't use when before return, and you will report an error

Note 1: Simulation parameters are either all simulated or all customized, and cannot be mixed and matched

There is a big hole here. If there is a private method or go in to execute, it is very likely that the parameters are wrong. For example, the parameters of your mock are anyString (), then you must pass an String instance instead of null, otherwise mock will fail. I am here before 1 straight is an attribute of the object, and directly new passes an object

So 1 straight unsuccessful:

For example, the method needs user. getId (), and your mock is an anyInt (), so you must give this user and setId (9527) when you really pass it, otherwise you can't achieve the expected simulation effect, and all methods are one! !


try {<br>          //  Method name , Method parameter , Must all correspond , Otherwise, the error reporting method cannot be found 
     PowerMockito.doReturn(1).when(orderService, "dateListMinBook",anyString(),anyString(),any(RoomType.class),anyString(),anyString());
     PowerMockito.doReturn(ResponseMessage.success().pushData("dateRoomTypeList",new ArrayList<DateRoomType>())).when(orderService, "eachDateNumAndPrice",any(Order.class),any(RoomType.class),anyBoolean(),anyInt(),anyString(),any(User.class));
     PowerMockito.doReturn("2000").when(orderService, "getKeeptimeByWxcidAndHotelidAndLevel",anyString(),anyString(),anyString());
     PowerMockito.doNothing().when(orderService, "getPayWay",any(),any(),any(),any(),any());
 } catch (Exception e) {
     e.printStackTrace();
 }
5 Expected results

verify: Determine how many times the method was executed: Determine whether the test passed

For example: verify (userService, times (1)). queryUser (any (anyInt (), anyString (), anyString ());

2 springboot Project Use

1 Dependence

@Test(expectedExceptions = BusinessException.class)
public void testAddSupplierAccount_genIdentityNoError() {
    //  Tell powermock , need mock All static methods of the class 
 PowerMockito.mockStatic(PasswordGenerator.class);
 
 final SupplierAccountDto supplierAccountDto = new SupplierAccountDto();
 supplierAccountDto.setName(" Xiao Ming ");
 final String randomPWd = "666"; 
 PowerMockito.when(supplierDao.selectByEmail(anyString()))
   .thenReturn(new ArrayList<HaitaoSupplier>());
 //  Static method mock
 PowerMockito.when(PasswordGenerator.genPwd()).thenReturn(randomPWd);
 PowerMockito.when(pwEncoder.encode(anyString())).thenReturn(randomPWd);
 PowerMockito.when(identityNoGenerator.genIdentityNo()).thenReturn(-1L);
 
 supplierServiceImpl.addSupplierAccount(supplierAccountDto); 
 verify(pwEncoder).encode(randomPWd);
}
0 2 Create a test base class

@Test(expectedExceptions = BusinessException.class)
public void testAddSupplierAccount_genIdentityNoError() {
    //  Tell powermock , need mock All static methods of the class 
 PowerMockito.mockStatic(PasswordGenerator.class);
 
 final SupplierAccountDto supplierAccountDto = new SupplierAccountDto();
 supplierAccountDto.setName(" Xiao Ming ");
 final String randomPWd = "666"; 
 PowerMockito.when(supplierDao.selectByEmail(anyString()))
   .thenReturn(new ArrayList<HaitaoSupplier>());
 //  Static method mock
 PowerMockito.when(PasswordGenerator.genPwd()).thenReturn(randomPWd);
 PowerMockito.when(pwEncoder.encode(anyString())).thenReturn(randomPWd);
 PowerMockito.when(identityNoGenerator.genIdentityNo()).thenReturn(-1L);
 
 supplierServiceImpl.addSupplierAccount(supplierAccountDto); 
 verify(pwEncoder).encode(randomPWd);
}
1 3 Create a specific test class

@Test(expectedExceptions = BusinessException.class)
public void testAddSupplierAccount_genIdentityNoError() {
    //  Tell powermock , need mock All static methods of the class 
 PowerMockito.mockStatic(PasswordGenerator.class);
 
 final SupplierAccountDto supplierAccountDto = new SupplierAccountDto();
 supplierAccountDto.setName(" Xiao Ming ");
 final String randomPWd = "666"; 
 PowerMockito.when(supplierDao.selectByEmail(anyString()))
   .thenReturn(new ArrayList<HaitaoSupplier>());
 //  Static method mock
 PowerMockito.when(PasswordGenerator.genPwd()).thenReturn(randomPWd);
 PowerMockito.when(pwEncoder.encode(anyString())).thenReturn(randomPWd);
 PowerMockito.when(identityNoGenerator.genIdentityNo()).thenReturn(-1L);
 
 supplierServiceImpl.addSupplierAccount(supplierAccountDto); 
 verify(pwEncoder).encode(randomPWd);
}
2 4 Simulate private and static methods

@PrepareForTest(OrderServiceImpl.class)  //  Classes that need to call private or static methods 
public class OrderControllerTest extends TestBase {
    private OrderServiceImpl orderServiceImpl; // When you need to call a private or static method , Can't be used @Mock, Need to @before Initialize properties 
    @Mock
    private OrderMapper orderMapper;
    @Mock
    private RestTemplateUtil restTemplateUtil;
    private Integer orderId;
    private String wxcid;
    @Before
    public void init(){
        // Handling private method simulation instances 
        orderServiceImpl = PowerMockito.spy(new OrderServiceImpl()); // Use spy Manual injection of attributes is required for simulation , Because there's nothing 
        ReflectionTestUtils.setField(orderController, "iOrderService", orderServiceImpl);
        ReflectionTestUtils.setField(orderServiceImpl, "orderMapper", orderMapper);
        ReflectionTestUtils.setField(orderServiceImpl, "restTemplateUtil", restTemplateUtil);
    }
    // Pure mock Test , Not loaded springContext, Execute mock Operation , Must mock Steps , Will not actually call 
    @InjectMocks
    private OrderController orderController=new OrderController();
    @Test
    public void cancelTest(){
        System.out.println("test start.....");
        // 1  Structural parameter 
        ininParams();
        // 2 mock Steps 
        mockStep();
        // 3  Perform an operation 
        ResponseMessage cancel = orderController.cancel(wxcid, orderId);
        assertEquals(0,(int)cancel.getCode());
    }
    private void mockStep() {
        Order order = new Order();
        order.setStatus(2);
        when(orderMapper.getOrderByOrderId(anyInt())).thenReturn(order);
        when(orderMapper.updateStatus(anyInt(),anyInt())).thenReturn(2);
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("code",0);
        when(restTemplateUtil.postToCri(anyString(),anyString(),any())).thenReturn(jsonObject);
        // Handling private methods , It must be written in this way 
        try {
            PowerMockito.doNothing().when(orderServiceImpl, "returnTicketTouser", anyString(),any());
            PowerMockito.doReturn(ErrorCode.SUCCESS).when(orderServiceImpl, "refoundAndGetCode", any(),any(),any(),any());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void ininParams() {
        wxcid="57af462dff475fe4644de32f08406aa8";
        orderId=25864;
    }
}

Note:

If it is a sub-module project, there can only be one startup class in springboot project, that is, the startup annotations of other startup classes of service, dao and common modules need to be commented out, otherwise the test startup will report an error


Related articles: