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)