Mockito
Mockito
概念
测试类型
单元测试(Unit test)
单元测试关注单一的类. 它们存在的目的是检查这个类中的代码是否按照期望正确运行.
集成测试(Integration test)
集成测试是检查开发的模块和其他模块整合时是否正常工作.
虽然集成测试的代码影响范围比单元测试要广, 但是集成测试和单元测试一样, 也是针对于开发者而言的.
端到端测试(End-to-End test)
用户测试系统,一般不需要测试替身
在项目中基本都是使用单元测试和集成测试,单元测试就是测试写的代码是否正确
用法
创建mock对象
对象 变量名=mock(对象.class);
比如List list=mock(List.class);
设置mock对象的行为
when(具体的带参数的方法).then(返回的结果)
when(list.add(“one”)).thenReturn(true);
如果没有设置,哪怕你创建mock对象list时候,直接调用list.add(“one”),list还是为空
校验
例子
verify(mockedList, atLeastOnce()).add(“one”);
verify(mockedList, times(1)).add(“two”);
verify(mockedList, times(3)).add(“three times”);
verify(mockedList, never()).isEmpty();
spy
包装对象,可以像操作普通的对象一样返回值
例子
List spy=spy(new ArrayList());
when(spy.size()).thenReturn(100);
spy.add(“one”);
spy.add(“two”);
断言
Assert,常见的有assertTrue、assertFalse、assertEquals
例子:Assert.assertTrue(list.add(“one”));
原理讲解
Mockito的原理是基于代理实现的,以设置mock对象行为为例,当你调用设置mock行为的方法时,实际上会将该行为存放在一个map中,而后当你调用该方法时,代理对象会先查询map中是否存在该方法,若存在则返回设置的值,若不存在则返回null
例子
自定义实现一个简单的mockito的when.thenReturn
package com.netease.mock;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.*;
/**
* Created by huangzilong1 on 4/18/2019.
*/
class MethodInfo {
private final MyCGLibInterceptor interceptor;
private final Method method;
private final Object[] args;
public MethodInfo(MyCGLibInterceptor interceptor, Method method, Object[] args) {
this.interceptor = interceptor;
this.method = method;
this.args = args;
}
@Override
public int hashCode() {
return interceptor.hashCode() + method.hashCode() + Arrays.hashCode(args);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MethodInfo) {
final MethodInfo otherMethodInfo = (MethodInfo) obj;
return interceptor.equals(otherMethodInfo.interceptor) && method.equals(otherMethodInfo.method) && Arrays.equals(args, otherMethodInfo.args);
}
return false;
}
@Override
public String toString() {
return "{interceptor: " + interceptor + ", Method: " + method + ", args: " + Arrays.toString(args) + "}";
}
public MyCGLibInterceptor getInterceptor() {
return interceptor;
}
public Method getMethod() {
return method;
}
public Object[] getArgs() {
return args;
}
}
class MockInjector {
private final MethodInfo methodInfo;
public void thenReturn(final Object mockResult) {
Test.MOCKED_METHODS.put(methodInfo, mockResult);
}
public MockInjector(MethodInfo methodInfo) {
this.methodInfo = methodInfo;
}
public MethodInfo getMethodInfo() {
return methodInfo;
}
}
//cglib代理
class MyCGLibInterceptor implements MethodInterceptor {
public Object getInstance(final Class<?> t) {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(t);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
final MethodInfo key=new MethodInfo(this,method,args);
final boolean hasMocked = Test.MOCKED_METHODS.containsKey(key);
if (!hasMocked) {
System.out.println("Initializing the mock for " + key.toString());
return key;
} else {
System.out.println("Returns the mock result:");
return Test.MOCKED_METHODS.get(key);
}
}
}
public class Test {
public static final Map<MethodInfo, Object> MOCKED_METHODS = new HashMap<>();
public static MockInjector when(Object methodCall) {
return new MockInjector((MethodInfo) methodCall);
}
public static MyCGLibInterceptor getInterceptor() {
return new MyCGLibInterceptor();
}
public static void main(String[] args) {
final List<String> myMockList1 = (List<String>) getInterceptor().getInstance(List.class);
final List<String> myMockList2 = (List<String>) getInterceptor().getInstance(List.class);
final Map<Integer, String> myMockMap = (Map<Integer, String>) getInterceptor().getInstance(Map.class);
Test.when(myMockList1.get(0)).thenReturn("Hello, I am James");
Test.when(myMockList1.get(2)).thenReturn("Hello, I am Billy");
Test.when(myMockList2.get(0)).thenReturn("Hello, I am Tom");
Test.when(myMockMap.get(10)).thenReturn("Hello, I am Bob");
System.out.println("myMockList1.get(0) = " + myMockList1.get(0));
System.out.println("myMockList1.get(2) = " + myMockList1.get(2));
System.out.println("myMockList2.get(0) = " + myMockList2.get(0));
System.out.println("myMockMap.get(10) = " + myMockMap.get(10));
}
}
项目中的Mockito讲解
//kaola-predelivery-compose-app test
package com.netease.kaola.predelivery.compose.service.construction.impl;
//BeanCopyCompServiceImplTest testCopy
@Test
public void testCopy() {
InvoiceOrderInfo invoiceOrderInfo = new InvoiceOrderInfo();
invoiceOrderInfo.setClientAccount("CLIENT_ACCOUNT");
InvoiceGoodsInfo goodsInfo = new InvoiceGoodsInfo();
goodsInfo.setSkuId("SKU");
goodsInfo.setGoodsTaxNum("GOODS_TAX");
InvoiceSellerInfo sellerInfo = new InvoiceSellerInfo();
sellerInfo.setInvoiceGoodsInfos(Lists.newArrayList(goodsInfo));
sellerInfo.setOrderId("ORDER_ID");
sellerInfo.setSellerTaxCode("TAX_CODE");
invoiceOrderInfo.setSellerInvoiceInfos(Lists.newArrayList(sellerInfo));
InvoiceInfoDTO invoiceInfoDTO = beanCopyCompService.copyTradeInvoiceOrderComp(invoiceOrderInfo);
assertEquals(invoiceInfoDTO.getSellerInfos().size(), invoiceOrderInfo.getSellerInvoiceInfos().size());
assertEquals(invoiceInfoDTO.getSellerInfos().get(0).getInvoiceGoods().size(),
invoiceOrderInfo.getSellerInvoiceInfos().get(0).getInvoiceGoodsInfos().size());
List<InvoiceInfoDTO> invoiceInfoDTOList = beanCopyCompService.copyTradeInvoiceOrderList(Lists.newArrayList(invoiceOrderInfo));
assertEquals(invoiceInfoDTOList.size(), 1);
}
//kaola-predelivery-compose-app test
package com.netease.kaola.predelivery.compose.service.delivery.impl;
//DeliveryPrepareServiceImplMockTest
@Test
public void testGetDeliveryOrderConds_PopPresaleFromItem() {
voList.get(0).getOrderVO().setSellSupplierType(1001);
voList.get(0).getOrderVO().setOrderImportType(ImportType.ZHIYOU);
voList.get(0).getOrderItemVOs().get(0).setPreSale(ControlStatus.YES);
when(preDeliveryDisconfConfigHolder.getPopPresaleFromItemEnable()).thenReturn(false);
List<PredeliveryOrderCond> deliveryOrderConds = deliveryPrepareService
.getDeliveryOrderConds(gorderFullWithOrdersVO, voList, prepreareOrderCacheData);
assertTrue(deliveryOrderConds.isEmpty());
when(preDeliveryDisconfConfigHolder.getPopPresaleFromItemEnable()).thenReturn(true);
deliveryOrderConds = deliveryPrepareService.getDeliveryOrderConds(gorderFullWithOrdersVO, voList, prepreareOrderCacheData);
assertEquals(deliveryOrderConds.size(), 1);
assertEquals(deliveryOrderConds.get(0).getType().intValue(), DeliveryCondEnum.POP_ORDER_PRESALE.intValue());
}
还有一些需要跨服务调用mock