mockito模拟测试框架心得2

    xiaoxiao2021-03-25  118

    package testmockito; import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; public class Test01 { @Test public void abcd() { // 模拟创建一个List对象 List mock = mock(List.class); // 使用mock的对象 mock.add(1); mock.clear(); // 验证add(1)和clear()行为是否发生 verify(mock).add(1); verify(mock).clear(); } @Test public void test01(){ List mock = mock(List.class); when(mock.get(1)).thenReturn(new RuntimeException()); Object object = mock.get(1); System.out.println(object); } //给调用的方法设置执行的时候抛出异常 @Test public void test02(){ //模拟List对象 List mock = mock(List.class); //当执行mock模拟对象的get(1)方法,抛出异常,RumtimeException() doThrow(new RuntimeException()).when(mock).get(1); //不调用get(1)方法是不会抛出异常的,当调用后,就会发现抛出了一个运行期异常 mock.get(1); } //验证模拟对象调用方法的顺序 @Test public void test03(){ //创建模拟对象 List mock = mock(List.class); //创建排序验证对象 InOrder mockList = inOrder(mock); //先后执行mock.add(1) mock.add(2) mock.add(1); mock.add(2); //之前的验证方式,是不考虑add方法调用顺序,只考虑是否调用该方法,如下先2后1是Ok的 verify(mock).add(2); verify(mock).add(1); //当使用排序对象来验证的话,就会发现必须遵守调用的顺序来验证,如下: mockList.verify(mock).add(1); mockList.verify(mock).add(2); //排序验证对象也可以同时验证多个mock对象,如下 HashMap mockMap = mock(HashMap.class); LinkedList mockLink = mock(LinkedList.class); mockLink.get(1); mockLink.get(2); mockMap.get(1); mockMap.get(2); //可以同时传入两个mock对象 InOrder inOrders = inOrder(mockMap,mockLink); //进行验证,验证时候指定不同的对象即可 /* * 如下,情况,验证方法是否执行时,验证的顺序必须与调用时顺序一致 * 即便分别是属于两个对象,但是既然是一个inOrder对象传入的,那就必须按照他们 * 的调用顺序来执行,即顺序为:mockLink.get(1)、mockLink.get(2)、mockMap.get(1)、mockMap.get(2) * 如果不遵守规则,就报错 */ inOrders.verify(mockLink).get(1); inOrders.verify(mockLink).get(2); inOrders.verify(mockMap).get(1); inOrders.verify(mockMap).get(2); } //验证从未发生过的模拟对象 @Test public void test04(){ List<String> mock = mock(List.class); List<String> mock2 = mock(List.class); List<String> mock3 = mock(List.class); mock.get(1); mock.get(2); mock.get(3); mock.get(4); //之前验证时, 传入never()进行验证是否调用过某个方法,如下 // verify(mock , never()).get(5); //现在可以验证某个mock对象从来没有调用过方法,传参为可变长参数,如下: verifyZeroInteractions(mock2 , mock3); } //调用了多个方法,如果没有将这些方法全部通过验证,那么可使用下面案例进行检查,看一下是否存在多余的方法调用 @Test public void test05(){ List mock = mock(List.class); mock.add(1); mock.add(2); mock.add(3); verify(mock).add(1); verify(mock).add(2); //上面调用了3次add方法,但是只验证了2次,所以指向下面的方法时,就会测试失败,因为并没有将add(3)方法也通过验证 verifyNoMoreInteractions(mock); } // 使用注解的方式创建模拟对象,如下相当于执行了方法mock(List.class),这样更利于阅读以及代码的重用 //但是,注解完成后直接使用还是不可以的,需要做一个初始化操作 /*可以将该代码写在@Before中,也可以单独写在测试方法中。 @Before public void before(){ MockitoAnnotations.initMocks(this); } */ @Mock private List list; @Test public void test06(){ //初始化模拟对象 MockitoAnnotations.initMocks(this); //在这里我们就不需要重复的创建list模拟对象了,直接使用在外面注解生成的模拟对象即可 when(list.get(1)).thenReturn("abcd"); System.out.println(list.get(1)); verify(list).get(1); } //连续设置方法的存根 @Test public void test07(){ //如下,我们给get(0)方法设置返回存根,是如下一次次调用thenReturn()方式设置 List<String> mock = mock(List.class); when(mock.get(0)).thenReturn("第1个值").thenReturn("第2个值").thenReturn("第3个值"); System.out.println(mock.get(0)); System.out.println(mock.get(0)); System.out.println(mock.get(0)); //上面方式设置代码编写有些冗余,我们可以简写一下 when(mock.get(1)).thenReturn("简写后的第1个值","简写后的第2个值","简写后的第3个值","简写后的第4个值"); //再次调用,会发现效果和我们上面的一样 System.out.println(mock.get(1)); System.out.println(mock.get(1)); System.out.println(mock.get(1)); System.out.println(mock.get(1)); //注意,如果重复为一个方法设置了存根,那么后面会覆盖前面的,如下,我们设置了get(2)的存根,并将其覆盖 when(mock.get(2)).thenReturn("被覆盖前的数据1" , "被覆盖前的数据1"); when(mock.get(2)).thenReturn("被覆盖后的数据1" , "被覆盖后的数据1"); //当我们再次执行的时候,就会发现,打印的是被覆盖后的数据 System.out.println(mock.get(2)); System.out.println(mock.get(2)); } //重置mock模拟对象 @Test public void test08(){ List mock = mock(List.class); //设置了mock对象get(1)方法返回值 when(mock.get(1)).thenReturn("the Return Value"); //重置模拟对象 reset(mock); //打印结果发现值为null,mock对象被重置 System.out.println(mock.get(1)); } //将模拟对象设置给测试对象中,使用given方式设置 /* * 测试Service的getPerson方法,思路如下 * service调用Dao对象的getPerson方法获取Person对象 * Dao对象在Service对象构造器中传入但是不需要创建Dao对象 * 模拟一个Dao对象传入 * 设置Dao的getPerson的返回值 */ @Test public void test09(){ //创建Dao模拟对象 Dao mock = mock(Dao.class); //创建service对象 Service service = new Service(mock); //设定了当调用模拟对象mock的getPerson方法,那么返回的内容将是下面设定的,而不是在Dao类中定义的 when(mock.getPerson()).thenReturn(new Person("小赵","21")); //获取信息打印,发现信息是手动设置的小赵,而不是Dao类中的小明,并且Dao的构造器方法并没有真的执行 String info = service.getInfo(); System.out.println(info); } //注解方式注入 //通过该方式相当于spy(new Person()) @Spy ArrayList spy = new ArrayList(); @Test public void test10(){ MockitoAnnotations.initMocks(this); spy.add("abd"); System.out.println(spy.get(0)); when(spy.size()).thenReturn(123); } } class Service{ Dao dao; public Service(Dao dao){ this.dao = dao; } String name = "abcd"; String getInfo(){ return dao.getPerson( ).toString(); } } class Dao{ public Dao(){ //在这个模拟案例中,该构造器方法是不会执行的 System.out.println("执行了Dao的构造器方法"); } Person getPerson(){ return new Person("小明" , "12"); } } class Person{ String name; String age; public Person(String name , String age){ this.name = name; this.age = age; } public String toString(){ return "name:" + name + "age:" + age; } public void working(){ System.out.println("苦逼的敲代码"); } public String getInfo(){ return name; } }
    转载请注明原文地址: https://ju.6miu.com/read-14213.html

    最新回复(0)