Mockito各場景使用介紹


場景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)

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM