码迷,mamicode.com
首页 > 其他好文 > 详细

Mockito各场景使用介绍

时间:2018-08-21 15:12:49      阅读:673      评论:0      收藏:0      [点我收藏+]

标签:文档   depend   targe   bank   tde   party   class   https   vat   

场景1:某三方接口所有方法都需要Mock

实现方式1-配置configrution bean

实现方式2-在application context中配置mock bean

场景2:某三方接口部分方法mock

实现方式1-spy方式:

实现方式2-callRealMethod():

场景3:影响范围只在单个测试类

实现方式1-使用ReflectionTestUtils解决依赖注入Mock对象

实现方式2-官方介绍的@mock,@injectMock方式

场景4.mock代理类

实现方式1-通过AddtionalAnswer.delegateto(instance)

场景1:某三方接口所有方法都需要Mock

实现方式1-配置configrution bean

step1:创建一个类如下:

@Configuration

public class WithdrawConfiguration {

    @Bean

    @Primary

    public SauronBankService sauronBankService() {

        SauronBankService mock = mock(SauronBankService.class);

        BankCardDTO t = new BankCardDTO();

        t.setBankId((short) 11);

        t.setCardholder("hehe");

        t.setCardId("32423423423");

        t.setBankName("中国银行 ");

        t.setAcc_type((byte) 1);

        t.setBranch_bank_name("武汉分行");

        t.setProvince("湖北省");

        t.setCity("武汉市");

        when(mock.queryBankCard(anyInt(), anyLong(), Mockito.<String> any()))

                .thenReturn(t);        

        return mock;

    }

    

    @Bean

    @Primary

    public MasspayClient masspayClient() {

        // then return this.

        MasspayClient client = Mockito.mock(MasspayClient.class);

        MasspayResult<WithdrawResponse> withdrawResponseMasspayResult = new MasspayResult<>(

                ResultCode.SUCCESS);

        when(client.callLadon(any(WithdrawRequest.class)))

                .thenReturn(withdrawResponseMasspayResult);

        MasspayResult<CancelResponse> cancelResponseMasspayResult = new MasspayResult<>(

                ResultCode.SUCCESS);

        when(client.cancelCallLadon(any(CancelRequest.class)))

                .thenReturn(cancelResponseMasspayResult);

        return client;

    }

}

step2.在application context中加载如下:

实现方式2-在application context中配置mock bean

step1:pom文件中加载mockito dependency

step2:在application context中声明mock bean,参考如下:

<bean id="mockOrderManageFacade" class="org.mockito.Mockito"

  factory-method="mock">

<constructor-arg value="me.ele.transcore.comm.facade.api.OrderManageFacade">

</constructor-arg>

</bean>

注意事项:

<!-- id必须和biz中autowired的属性值一致,然后在测试类中@Resource该对象,stub该对象的方法指定返回数据 -->

<!-- 对其他测试类的影响:有关联测试类调用该接口时,接口中的其他方法默认返回null;解决影响:在其他相关联的测试指定返回值 -->

step3:在测试类中添加mock代码,参考如下:

        MockitoAnnotations.initMocks(this);//初始化mock bean

        WithdrawCancelCallBackResponse mockResponse = new WithdrawCancelCallBackResponse();

        mockResponse.setResultCode(

                ResultCodeEnum.FAIL_WITHDRAW_CALLBACK_AMOUNT_NO_CONSISTENT

                        .getKey());//

        Mockito.when(mockOrderManageFacade.withdrawCancelCallBack(

                Mockito.any(WithdrawCancelCallBackRequest.class)))

                .thenReturn(mockResponse);//mock为期望的response

场景2:某三方接口部分方法mock

  1. 部分mock解释说明:部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing(桩实现)
  2. mockito实现部分mock的两种方式:spy和callRealMethod()
  3. Spy类就可以满足我们的要求。如果一个方法定制了返回值或者异常,那么就会按照定制的方式被调用执行;如果一个方法没被定制,那么调用的就是真实类的方法。
  4. 如果我们定制了一个方法A后,再下一个测试方法中又想调用真实方法,那么只需在方法A被调用前,调用Mockito.reset(spyObject)。

实现方式1-spy方式:

    @Test

    public void spy_Simple_demo(){

        List<String> list = new LinkedList<String>();  

        List<String> spy = spy(list);  

        when(spy.size()).thenReturn(100); 

        spy.add("one");  

        spy.add("two");  

        

/*      spy的原理是,如果不打桩默认都会执行真实的方法,如果打桩则返回桩实现。

        可以看出spy.size()通过桩实现返回了值100,而spy.get(0)则返回了实际值*/

        assertEquals(spy.get(0), "one");  

        assertEquals(100, spy.size());  

    }

注意事项:当调用方法如when().thenReturn()时,实际上还是调用了实际方法。

参考如下:

      @Test  

    public void spy_Procession_Demo() {  

        Jack spyJack = spy(new Jack());  

        //使用spy的桩实现实际还是会调用stub的方法,只是返回了stub的值

        when(spyJack.go()).thenReturn(false);  

        assertFalse(spyJack.go()); 

        

        //不会调用stub的方法

        doReturn(false).when(spyJack).go();

        assertFalse(spyJack.go()); 

    } 

    

实现方式2-callRealMethod():

package callRealMethod;

 

import org.junit.Test;

import static org.mockito.Mockito.*;

 

public class CallMethodDemo {

    @Test  

    public void callRealMethodTest() {  

        Jerry jerry = mock(Jerry.class);  

      

        doCallRealMethod().when(jerry).doSomeThingA();  

        doCallRealMethod().when(jerry).doSomeThingB();  

      

        jerry.goHome();  

      

        verify(jerry).doSomeThingA();  

        verify(jerry).doSomeThingB();  

    }  

}

 

class Jerry {  

    public void goHome() {  

        doSomeThingA();  

        doSomeThingB();  

    }  

  

    // real invoke it.  

    public void doSomeThingB() {  

        System.out.println("good day");  

  

    }  

  

    // auto mock method by mockito  

    public void doSomeThingA() {  

        System.out.println("you should not see this message.");  

  

    }  

}

场景3:影响范围只在单个测试类

优点:mock对象影响范围只在单个测试类,不影响其他测试类。

实现方式1-使用ReflectionTestUtils解决依赖注入Mock对象

@Component

public class WithdrawApplicationTest extends AccountWithdrawFacadeBaseTest {

    @Captor

    private ArgumentCaptor<WithdrawApplicationRequest> captor;

    @Mock

    private CheckPasswordComponent mockCheckPasswordComponent;

    @Autowired

    private CheckPasswordComponent checkPasswordComponent;

    @Autowired

    private AccountWithdrawWithoutLadonBiz acccountWithdrawWithoutLadonBiz;

    @Autowired

    private AccountWithdrawFacade withdrawFacade;

    

    @Test

    public void withdrawTest() {

        WithdrawApplicationRequest applyReq = new WithdrawApplicationRequest();

        applyReq.setAccountType(TYPE);

        applyReq.setCustomerId(ZEUS_CUSTOMER_ID);

        applyReq.setRequestPartyId(ZEUS_SOURCE_PARTY_ID);

        applyReq.setSourcePartyId(ZEUS_SOURCE_PARTY_ID);

        applyReq.setTransactionChannel("h5");

        applyReq.setPassword(ZEUS_PASSWORD);

        applyReq.setPartyTransactionId(

                new Timestamp(System.currentTimeMillis()).toString());

        applyReq.setPartyTransactionTime(

                new Timestamp(System.currentTimeMillis()));

        applyReq.setTransAmount(new BigDecimal("1000"));

        applyReq.setSign(GenerateSignUtils.generateSign(applyReq,

                "fd219e782ecebf0bc8f4a83e43248b45"));

 

        given(mockCheckPasswordComponent.restCountByPassword(Mockito.anyInt(),

                Mockito.anyLong(), Mockito.anyByte())).willReturn(3);

 

        WithdrawApplicationResponse response = withdrawFacade

                .withdrawApplication(applyReq);

 

        verify(mockCheckPasswordComponent, times(1)).restCountByPassword(

                Mockito.anyInt(), Mockito.anyLong(), Mockito.anyByte());

        Assert.assertEquals(response.getRestAttempts(), 3);

        System.err.println(JsonUtil.toFormatJson(response));

        Assert.assertEquals(response.getTransactionResultDescription(), "成功");

    }

    

    @BeforeClass

    private void beforeClass() {

        MockitoAnnotations.initMocks(this);

        try {

            ReflectionTestUtils.setField(

                    AopTargetUtils.getTarget(acccountWithdrawWithoutLadonBiz),

                    "checkPasswordComponent", mockCheckPasswordComponent);

        } catch (Exception e) {

            logger.error("", e);

        }

    }

 

    @AfterClass

    public void clearMocks() throws Exception {

        ReflectionTestUtils.setField(

                AopTargetUtils.getTarget(acccountWithdrawWithoutLadonBiz),

                "checkPasswordComponent", checkPasswordComponent);// 还原为真实bean,不影响其他case

    }

}

实现方式2-官方介绍的@mock,@injectMock方式

说明:据实验,这种模式碰到多层内嵌bean时不生效,所以暂不举例说明,参考如下文档。

官方文档参考:https://static.javadoc.io/org.mockito/mockito-core/2.10.0/org/mockito/Mockito.html

 

场景4.mock代理类

实现方式1-通过AddtionalAnswer.delegateto(instance)

 

技术分享图片

 

 

转载:https://www.cnblogs.com/danqiu/p/7531538.html 

Mockito各场景使用介绍

标签:文档   depend   targe   bank   tde   party   class   https   vat   

原文地址:https://www.cnblogs.com/ceshi2016/p/9510895.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!