mockito

Mockito是一个用于单元测试和集成测试的Java框架,它允许创建mock对象并设定其行为。本文介绍了Mockito的基本概念,如单元测试、集成测试和端到端测试,并详细说明了如何创建mock对象、设置行为、进行校验和使用spy。同时,还解释了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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值