Summary of common scenarios for writing java test code


If you want to write zero defect code, writing test code is the key. The validity and reliability of the test code is also very important, so I recently wrote a little bit of test code and summarized "100 million" practical skills.

1, How to access private methods or properties of a class

1.1 if a class can construct an instance

Suppose we have a class Student with private methods and private member variables, as follows:

class Student{
    private String hobby;
    private String readBook(String book){
     return "happiness";
   }
}

So how can you easily access them in unit test code through jmock? Your first thought is to use reflection to access them:

Private methods also include the following methods:

Method method= Student.class.getDeclaredMethod("readBook",String.class);
method.setAccessible(true);
method.invoke(student, "aBook");
 

Supplementary notes:

  • If the function parameters tested above are not specific objects, such as String, List/Map of parent class, we only need to pass in List.class/Map.class;
  • Remember that getClass() is different from XX.class. Remember not to use it wrong.

In addition to using reflection directly, you can also use
Deencapsulation can be called gracefully (it is more convenient to obtain the return value without handling exception capture and asset determination)

 
import mockit.Deencapsulation;
 
Student student = new Student();
//Among them“ EnglishBook"Is passed in to readBook()Method, gains yes readBook()Method.
String hobby = Deencapsulation.invoke(student, "hobby");
String gains =Deencapsulation.getField(student, "readBook", "EnglishBook");
Assert.assertEquals("happiness", gains);

1.2 if the class cannot be instantiated

class Computer{
     private Computer(){
    )
     private static String surf(String book){
     return "happiness";
)

In this case, reflection and Deencapsulation can also be used to obtain private methods

Method functionName=AUtil.class.getDeclaredMethod("functionName", String.class, String.class);
functionName.setAccessible(true);
functionName.invoke(AUtil.class,"id","name");//The return value is not obtained normally
String gain = Deencapsulation.invoke(Computer.class, "surf", "book");
Assert.assertEquals("happiness", gains);

2, How to the constructor of mock class

First of all, why should we use the constructor of mock class? Because the class constructor in some business scenarios is complex and not easy to construct, it is very necessary to mock the constructor
The method is as follows:

new MockUp<NeedToMockClass>{
    @Mock
    public void $init(){
 
    }
 
    @Mock
    public coid $init(String[] args){
 
    }
}

Next, list the actual scenarios
The existing objects requiring mock are as follows:
The mock scenario is as follows: when writing test code, we need to focus on the code segments 1 and 2 of the function generateResBeans. We don't pay attention to the Resolver object and its function build (covered in other test classes), so we need to mock its constructor

public List<ResBean> generateResBeans(Model model){
        //...code segment 1
        Resolver resolver= new Resolver(model);
        List<Res> resList = resolver.build();
       //...code segment 2
}

Therefore, it is used in the test code

public void should_success_when_build_successfully() throws Exception {
    new MockUp<Resolver>(){
        @Mock
        public void $init(Model model){
            this.model = model;
        }   
        @Mock
        public List<Res> build(){
            return new ArrayLIst<>();
        }
    }
 
    Assert.assertTrue(generateResBeans(new Model("model")).isEmpty());
}

3, How to the private property of mock class

3.1 if the class attribute is non static

Use Whitebox.setlnternalState() to process the attributes of the classes that need mock. The existing class objects that need mock are as follows, where mock needs to call its attribute logger

public class Impl{
     private MyLog logger = AppLog.getLogger();
     public MyLog logger1 = AppLog.getLogger();
)

The test code is as follows:

import org.mockito.internal.util.reflection.Whitebox;
 
OssLog osslog = MOckito.mock(OssLog.class);
Impl impl = new Impl();
Whitebox.setInternalState(impl, "logger", ossLog);
Whitebox.setInternalState(impl, "logger1", ossLog);

impl.function(context,null);//verification function Will it print
Mockito.verify(ossLog,Mockito.never()).error(anyString()));

3.2 if the class attribute is static

This is not set directly by Whitebox.setlnternalState(). The usage is as follows:

static void setFinalStatic(Field field, Object newValue) throws Exception{
    field.setAccessible(true);//remove final moidfer from field
    Filed modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() &~Modifier.FINAL);
    field.set(null, newValue);
}

// If the attribute is not final, use the following method
static void setStatic(Field field, Object newValue) throws Exception{
    field.setAccessible(true);
    field.set(null, newValue);
}

The existing class objects requiring mock are as follows, where mock is required to call its property logger

public class Impl{
     private static final MyLog logger = AppLog.getLogger();
)

The test code is as follows:

import static org.mockito.Matchers.anyString;
 
OssLog ossLog=Mockito.mock(OssLog.class);
Impl impl =new Impl0);
setFinalStatic(Impl.class.getDeclaredField("logger"), ossLog);
 
impl.function(context,null);//verification function Will it print
Mockito.verify(ossLog,Mockito.never()).error(anyString()));

IV. verify whether the function is executed

4.1 if the function is non static and the class object can mock

The mock object is executed first, and then the mock object is executed

JobState mock=Mockito.mock(JobState.class);
mock.setState(state);//Execute business code
Mockito.verify(mock,times(1)).setState(state);
Mockito.verify(mock,never().setState(state);

Other uses of Mockito.verify:
https://blog.csdn.net/blueZhangFun/article/details/103665393

4.2 if the function is non static

Mockito is very powerful, but it does not support static methods. Therefore, Powermock is used.

(the above content is original by DreamKite, please attach the original link for reprint)

Tags: Java Back-end unit testing

Posted on Fri, 19 Nov 2021 19:38:21 -0500 by shocker-z