日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

《xUnit Test Patterns》学习笔记6 - Test Double

發(fā)布時(shí)間:2025/3/20 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《xUnit Test Patterns》学习笔记6 - Test Double 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我不知道Test Double翻譯成中文是什么,測(cè)試替身?Test Double就像是陳龍大哥電影里的替身,起到以假亂真的作用。在單元測(cè)試時(shí),使用Test Double減少對(duì)被測(cè)對(duì)象的依賴,使得測(cè)試更加單一,同時(shí),讓測(cè)試案例執(zhí)行的時(shí)間更短,運(yùn)行更加穩(wěn)定,同時(shí)能對(duì)SUT內(nèi)部的輸入輸出進(jìn)行驗(yàn)證,讓測(cè)試更加徹底深入。但是,Test Double也不是萬(wàn)能的,Test Double不能被過(guò)度使用,因?yàn)閷?shí)際交付的產(chǎn)品是使用實(shí)際對(duì)象的,過(guò)度使用Test Double會(huì)讓測(cè)試變得越來(lái)越脫離實(shí)際。

我感覺(jué),Test Double這玩意比較適合在Java,C#等完全面向?qū)ο蟮恼Z(yǔ)言中使用。并且需要很好的使用依賴注入(Dependency injection)設(shè)計(jì)。如果被測(cè)系統(tǒng)是使用C或C++開發(fā),使用Test Double將是一個(gè)非常困難和痛苦的事情。

要理解Test Double,必須非常清楚以下幾個(gè)東西的關(guān)系,本文的重點(diǎn)也是說(shuō)明一下他們之間的關(guān)系。他們分別是:

  • Dummy Object
  • Test Stub
  • Test Spy
  • Mock Object
  • Fake Object
  • Dummy Object

    Dummy Objects泛指在測(cè)試中必須傳入的對(duì)象,而傳入的這些對(duì)象實(shí)際上并不會(huì)產(chǎn)出任何作用,僅僅是為了能夠調(diào)用被測(cè)對(duì)象而必須傳入的一個(gè)東西。

    使用Dummy Object的例子:

    public?void?testInvoice_addLineItem_DO()?{
    ???????nal?
    int?QUANTITY?=?1;
    ??????Product?product?
    =?new?Product("Dummy?Product?Name",
    ????????????????????????????????????getUniqueNumber());
    ??????Invoice?inv?
    =?new?Invoice(?new?DummyCustomer()?);
    ??????LineItem?expItem?
    =?new?LineItem(inv,?product,?QUANTITY);
    ??????
    //?Exercise
    ??????inv.addItemQuantity(product,?QUANTITY);
    ??????
    //?Verify
    ??????List?lineItems?=?inv.getLineItems();
    ??????assertEquals(
    "number?of?items",?lineItems.size(),?1);
    ??????LineItem?actual?
    =?(LineItem)lineItems.get(0);
    ??????assertLineItemsEqual(
    "",?expItem,?actual);
    }

    ?

    Test Stub

    測(cè)試樁是用來(lái)接受SUT內(nèi)部的間接輸入(indirect inputs),并返回特定的值給SUT。可以理解Test Stub是在SUT內(nèi)部打的一個(gè)樁,可以按照我們的要求返回特定的內(nèi)容給SUT,Test Stub的交互完全在SUT內(nèi)部,因此,它不會(huì)返回內(nèi)容給測(cè)試案例,也不會(huì)對(duì)SUT內(nèi)部的輸入進(jìn)行驗(yàn)證。

    使用Test Stub的例子:

    public?void?testDisplayCurrentTime_exception()
    ?????????
    throws?Exception?{
    ??????
    //?Fixture?setup
    ??Testing?with?Doubles?136?Chapter?11????Using?Test?Doubles
    ??????
    //???De?ne?and?instantiate?Test?Stub
    ??????TimeProvider?testStub?=?new?TimeProvider()
    ?????????{?//?Anonymous?inner?Test?Stub
    ????????????public?Calendar?getTime()?throws?TimeProviderEx?{
    ???????????????
    throw?new?TimeProviderEx("Sample");
    ?????????}
    ??????};
    ??????
    //???Instantiate?SUT
    ??????TimeDisplay?sut?=?new?TimeDisplay();
    ??????sut.setTimeProvider(testStub);
    ??????
    //?Exercise?SUT
    ??????String?result?=?sut.getCurrentTimeAsHtmlFragment();
    ??????
    //?Verify?direct?output
    ??????String?expectedTimeString?=
    ????????????
    "<span?class=\"error\">Invalid?Time</span>";
    ??????assertEquals(
    "Exception",?expectedTimeString,?result);
    }

    ?

    Test Spy

    Test Spy像一個(gè)間諜,安插在了SUT內(nèi)部,專門負(fù)責(zé)將SUT內(nèi)部的間接輸出(indirect outputs)傳到外部。它的特點(diǎn)是將內(nèi)部的間接輸出返回給測(cè)試案例,由測(cè)試案例進(jìn)行驗(yàn)證,Test Spy只負(fù)責(zé)獲取內(nèi)部情報(bào),并把情報(bào)發(fā)出去,不負(fù)責(zé)驗(yàn)證情報(bào)的正確性

    使用Test Spy的例子:

    public?void?testRemoveFlightLogging_recordingTestStub()
    ????????????
    throws?Exception?{
    ??????
    //?Fixture?setup
    ??????FlightDto?expectedFlightDto?=?createAnUnregFlight();
    ??????FlightManagementFacade?facade?
    =
    ????????????
    new?FlightManagementFacadeImpl();
    ??????
    //????Test?Double?setup
    ??????AuditLogSpy?logSpy?=?new?AuditLogSpy();
    ??????facade.setAuditLog(logSpy);
    ??????
    //?Exercise
    ??????facade.removeFlight(expectedFlightDto.getFlightNumber());
    ??????
    //?Verify?state
    ??????assertFalse("?ight?still?exists?after?being?removed",
    ??????????????????facade.?ightExists(?expectedFlightDto.
    ????????????????????????????????????????????getFlightNumber()));
    ??????
    //?Verify?indirect?outputs?using?retrieval?interface?of?spy
    ??????assertEquals("number?of?calls",?1,
    ???????????????????
    logSpy.getNumberOfCalls());
    ??????assertEquals(
    "action?code",
    ???????????????????Helper.REMOVE_FLIGHT_ACTION_CODE,
    ???????????????????
    logSpy.getActionCode());
    ??????assertEquals(
    "date",?helper.getTodaysDateWithoutTime(),
    ???????????????????
    logSpy.getDate());
    ??????assertEquals(
    "user",?Helper.TEST_USER_NAME,
    ???????????????????
    logSpy.getUser());
    ??????assertEquals(
    "detail",
    ???????????????????expectedFlightDto.getFlightNumber(),
    ???????????????????
    logSpy.getDetail());
    }


    Mock Object

    Mock Object和Test Spy有類似的地方,它也是安插在SUT內(nèi)部,獲取到SUT內(nèi)部的間接輸出(indirect outputs),不同的是,Mock Object還負(fù)責(zé)對(duì)情報(bào)(indirect outputs)進(jìn)行驗(yàn)證,總部(外部的測(cè)試案例)信任Mock Object的驗(yàn)證結(jié)果。

    Mock的測(cè)試框架有很多,比如:NMock,JMock等等。如果使用Mock Object,建議使用現(xiàn)成的Mock框架,因?yàn)榭蚣転槲覀冏隽撕芏喱嵥榈氖虑?#xff0c;我們只需要對(duì)Mock對(duì)象進(jìn)行一些描述。比如,通常Mock框架都會(huì)使用基于行為(Behavior)的描述性調(diào)用方法,即,在調(diào)用SUT前,只需要描述Mock對(duì)象預(yù)期會(huì)接收什么參數(shù),會(huì)執(zhí)行什么操作,返回什么內(nèi)容等,這樣的案例更加具有可讀性。比如下面使用Mock的測(cè)試案例:

    public?void?testRemoveFlight_Mock()?throws?Exception?{
    ??????
    //?Fixture?setup
    ??????FlightDto?expectedFlightDto?=?createAnonRegFlight();
    ??????
    //?Mock?con?guration
    ??????Con?gurableMockAuditLog?mockLog?=
    ?????????
    new?Con?gurableMockAuditLog();
    ??????mockLog.setExpectedLogMessage(
    ???????????????????????????helper.getTodaysDateWithoutTime(),
    ???????????????????????????Helper.TEST_USER_NAME,
    ???????????????????????????Helper.REMOVE_FLIGHT_ACTION_CODE,
    ???????????????????????????expectedFlightDto.getFlightNumber());
    ??????mockLog.setExpectedNumberCalls(1);
    ??????
    //?Mock?installation
    ??????FlightManagementFacade?facade?=
    ????????????
    new?FlightManagementFacadeImpl();
    ??????facade.setAuditLog(mockLog);
    ??????
    //?Exercise
    ??????facade.removeFlight(expectedFlightDto.getFlightNumber());
    ??????
    //?Verify
    ??????assertFalse("?ight?still?exists?after?being?removed",
    ??????????????????facade.?ightExists(?expectedFlightDto.
    ?????????????????????????????????????????????getFlightNumber()));
    ??????mockLog.verify();
    }


    Fake Object

    經(jīng)常,我們會(huì)把Fake Object和Test Stub搞混,因?yàn)樗鼈兌己屯獠繘](méi)有交互,對(duì)內(nèi)部的輸入輸出也不進(jìn)行驗(yàn)證。不同的是,Fake Object并不關(guān)注SUT內(nèi)部的間接輸入(indirect inputs)或間接輸出(indirect outputs),它僅僅是用來(lái)替代一個(gè)實(shí)際的對(duì)象,并且擁有幾乎和實(shí)際對(duì)象一樣的功能,保證SUT能夠正常工作。實(shí)際對(duì)象過(guò)分依賴外部環(huán)境,Fake Object可以減少這樣的依賴。需要使用Fake Object通常符合以下情形:

  • 實(shí)際對(duì)象還未實(shí)現(xiàn)出來(lái),先用一個(gè)簡(jiǎn)單的Fake Object代替它。
  • 實(shí)際對(duì)象執(zhí)行需要太長(zhǎng)的時(shí)間
  • 實(shí)際對(duì)象在實(shí)際環(huán)境下可能會(huì)有不穩(wěn)定的情況。比如,網(wǎng)絡(luò)發(fā)送數(shù)據(jù)包,不能保證每次都能成功發(fā)送。
  • 實(shí)際對(duì)象在實(shí)際系統(tǒng)環(huán)境下不可用,或者很難讓它變得可用。比如,使用一個(gè)依賴實(shí)際數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)訪問(wèn)層對(duì)象,必須安裝數(shù)據(jù)庫(kù),并且進(jìn)行大量的配置,才能生效。
  • 一個(gè)使用Fake Object的例子是,將一個(gè)依賴實(shí)際數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)訪問(wèn)層對(duì)象替換成一個(gè)基于內(nèi)存,使用Hash Table對(duì)數(shù)據(jù)進(jìn)行管理的數(shù)據(jù)訪問(wèn)層對(duì)象,它具有和實(shí)際數(shù)據(jù)庫(kù)訪問(wèn)層一樣的接口實(shí)現(xiàn)。

    public?class?InMemoryDatabase?implements?FlightDao{
    ???
    private?List?airports?=?new?Vector();
    ???
    public?Airport?createAirport(String?airportCode,
    ????????????????????????String?name,?String?nearbyCity)
    ????????????
    throws?DataException,?InvalidArgumentException?{
    ??????assertParamtersAreValid(??airportCode,?name,?nearbyCity);
    ??????assertAirportDoesntExist(?airportCode);
    ??????Airport?result?
    =?new?Airport(getNextAirportId(),
    ????????????airportCode,?name,?createCity(nearbyCity));
    ??????airports.add(result);
    ??????
    return?result;
    ???}
    ???
    public?Airport?getAirportByPrimaryKey(BigDecimal?airportId)
    ????????????
    throws?DataException,?InvalidArgumentException?{
    ??????assertAirportNotNull(airportId);
    ??????Airport?result?
    =?null;
    ??????Iterator?i?
    =?airports.iterator();
    ??????
    while?(i.hasNext())?{
    ?????????Airport?airport?
    =?(Airport)?i.next();
    ?????????
    if?(airport.getId().equals(airportId))?{
    ????????????
    return?airport;
    ?????????}
    ??????}
    ??????
    throw?new?DataException("Airport?not?found:"+airportId);
    }


    說(shuō)了這么多,可能更加糊涂了。在實(shí)際使用時(shí),并不需要過(guò)分在意使用的是哪種Test Double。當(dāng)然,作為思考,可以想一想,以前測(cè)試過(guò)程中做的一些所謂的“假的”東西,到底是Dummy Object, Test Stub, Test Spy, Mock Object, 還是Fake Object呢?

    總結(jié)

    以上是生活随笔為你收集整理的《xUnit Test Patterns》学习笔记6 - Test Double的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲综合色小说 | 国产精品久久久久久久久久辛辛 | 黄黄的网站 | 美女视频黄的免费 | 欧美 亚洲 激情 一区 | 温柔女教师在线观看 | 国产又粗又猛又爽又黄91 | 亚洲免费在线视频 | 国产高清片 | 日本一本视频 | 按摩害羞主妇中文字幕 | 日韩三级麻豆 | 国产麻豆免费观看 | 重囗味sm一区二区三区 | 中文免费av | 欧美色图第一页 | 欧美精品小视频 | 致单身男女免费观看完整版 | 日韩免费看 | 999久久久精品视频 亚洲视频精品在线 | 久久短视频 | 成人综合在线视频 | 中文字幕一区二区三区日韩精品 | 嫩草视频免费观看 | 一边摸一边抽搐一进一出视频 | 日本一区二区精品视频 | 欧美黄网在线观看 | 国产黄色观看 | av免费在线观看网站 | 日产精品久久久久久久 | 狠狠爱欧美 | 国产精品久久久久久久久久久新郎 | 精品人妻无码专区在线 | 中文字幕欧美专区 | 国产精品无码久久久久久 | 在线观看一区二区视频 | 日本免费a视频 | 中文字幕乱码中文字幕 | av激情四射| 国产午夜福利一区 | 欧美精品一卡二卡 | 夜夜嗨av一区二区三区免费区 | 免费在线观看视频 | 国产人妻一区二区三区四区五区六 | 久久蜜桃精品 | 国产夜色精品一区二区av | 爱情岛论语亚洲入口 | 日韩av影音先锋 | 乱子伦视频在线看 | 国产福利合集 | 欧美一区二区三区啪啪 | 九九爱爱视频 | 欧美日韩国产一区二区三区在线观看 | 亚洲激情中文字幕 | 韩国一区二区三区四区 | 黑人高潮一区二区三区在线看 | 国产精品久久久久久免费 | 狠狠干老司机 | 懂色av蜜臀av粉嫩av喷吹 | 成人在线网站 | 亚洲视频小说 | 婷婷激情五月综合 | 在线观看av网页 | 久久久久久久久影院 | 国产精品黄 | 日韩av三级在线 | 97久久综合| 中国一级大黄大黄大色毛片 | 激情小说在线观看 | 亚洲精品一区在线 | 国产成人精品免高潮费视频 | 三上悠亚一区二区三区 | 成人性生交大免费看 | 九九色精品 | 99精品视频免费观看 | 人妻视频一区二区 | 日韩精品理论 | av片子在线观看 | 爽天天天天天天天 | 午夜精品在线观看 | 国产乱码在线 | 国产成人免费在线观看 | 欧美日性视频 | 色综合视频在线 | 午夜视频久久久 | 欧美午夜精品一区二区三区电影 | 亚洲五级片 | 国产一区亚洲 | 亚洲美女网站 | 又污又黄的网站 | 91久色蝌蚪| 全部免费毛片 | 青青草91 | 国内视频一区二区三区 | 亚洲一二三四五 | 国产成人精品无码免费看夜聊软件 | 夜福利视频 | 欧美啪啪一区 | 欧美大片免费观看网址 |