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;
}
}
mockito模拟测试框架心得2
最新推荐文章于 2023-07-04 10:26:17 发布