天天看點

單測的心得體會

背景介紹:

目前開發的項目基本都是基于dubbo進行遠端服務調用。由于自身項目比較複雜(主要在于内部實體類之間轉換過于複雜以及系統依賴服務較多導緻調用鍊過長),造成自身無法簡單的使用postman這些工具進行接口測試,且項目過大 内部開發往往需要将本地代碼push上去再容器部署,一個小小的bug修改部署成本極大(往往要十五分鐘)。最近寫的第二個項目由于傳參NPE 問題進行了十多次修改,可想而知部署成本極大。由此懂得單測的必要性。

我們部門主要使用spook+grooy進行單元測試。簡單介紹如何使用grooy和spook實作簡潔單元測試以及今天寫單測遇到的一個坑。

原先代碼中使用junit4配合Mockito 進行測試 發現對于特定條件判斷往往代碼量大,而且備援。觀摩以前的代碼往往發現其中大部份測試都是對結果非空判斷,如果遇到多條件的情況想要具體結果需要大量when() thenReturn();

spook進行單測好處是模版簡單,代碼簡潔,對于特定資料可以清晰判斷。

使用spook進行單測主要模版為 expect-where , when-then-thrown, setup-given-when-then[-where]

比如:這是最近寫的一個例子可以簡單的看作setup-given-when-then[-where] 這種形式

def "testFXSupplierName"(){
        setup:
        def shopClient = Mock(ShopClient)
        OrderSearchServiceImpl service = new OrderSearchServiceImpl()
        service.shopClient = shopClient
        when:
        List<OrderBO> orderBOList=[new OrderBO(xxxx:new xxxx(extra: ["xxxx":2],tags:["xxxx":true]))]
        OrderPageBO orderPageBO=new OrderPageBO(list: orderBOList)
        shopClient.queryShopMetaInfos(_) >> new ShopMetaInfosQueryResult(shopMetaInfos:[new ShopMetaInfo(xxxx: 2,xxxxx: "test")])
        service.supplierOrderPutSupplierName(orderBOList)
        then:
        orderPageBO.getList().get(0).getOrderMain().getExtra().get("xxxx")=="test"
    }           

setup:建立要mock的實體類

given:建立傳回的對象實體

when:将given中建立的對象實體指派mock實體方法調用或進行方法調用

then:結果比較

where:多條件添加

這也是一個例子

@Unroll()  //這邊是标記資訊可以打标
    def 'presell_normal'() {
        setup:
        def tradeSku = new TradeSku(preSale: presell)
        def goods = new Goods(num: num, price: price)
        def icGoods = new IcGoods(depositType: depositType,
                                                        depositRatio: depositeRatio,
                                                        deposit: deposite)
        tradeSku.setIcGoodsPreSaleInfo(icGoods)
        expect:
        def value = TradeGroupConvertUtil.preSell(tradeSku, goods)
        value == res
        where:
        presell << [1, 1, 1, 1, 1, 1, 1, 1, 0, 0]
        depositType << [0, 0, 0, 0, 1, 1, 1, 1, 0, 0]
        depositeRatio << [40, 20, 30, 80, 1, 2, 3, 4, 0, 0]
        num << [1, 2, 3, 4, 1, 2, 3, 4, 0, 0]
        price << [100, 100, 100, 100, 100, 100, 100, 100, 0, 0]
        deposite << [40, 20, 30, 80, 1, 2, 200, 4, 0, 0]
        res << ['40', '40', '90', '320', '1', '4', '300', '16', '', '']
    }           

對于異常場景可以使用這種

def 'getpreSell_error'() {
        setup:
        def tradeSku = new TradeSku(preSale: presell)
        def goods = new Goods(num: num, price: price)
        def icGoods = new IcGoods(depositType: depositType,
                                                        depositRatio: depositeRatio,
                                                        deposit: deposite)
        tradeSku.setIcGoods(icGoods)
        when:
        TradeGroupConvertUtil.preSell(tradeSku, goods)
        then:
        def ex = thrown(Exception)
        expect:
        ex.message == errorMessage
        where:
        presell << [1, 1, 1, 1, 1, 1,]
        depositType << [0, 0, 0, 0, 1, 1,]
        depositeRatio << [-12, 0, 100, 120, 200, 300]
        num << [1, 2, 3, 4, 1, 2]
        price << [100, 100, 100, 100, 100, 100]
        deposite << [40, 20, 30, 80, null, 0]
        errorMessage <<
        ["xxxxxx異常資訊", "xxxxxx異常資訊", "xxxxxx異常資訊", "xxxxxx異常資訊", "xxxxxx異常資訊", "xxxxxx異常資訊"]

    }           

這邊就是主要使用的三個例子,需要異常抛出的情況不能和正常情況一起使用。需要區分為兩個測試方法。

遇到的坑:

今晚寫一個單測,仿照項目中原先的老代碼寫的。對于代碼中mock使用的是Mockito注解方式,發現使用注解方式可以擷取到這個類但是對于使用grooy 文法進行方法調用指派一直為null但是注入的類不為空否則會報NPE問題。後來通過重新使用mock()注入解決這個問題。得出結論使用何種方式注入就要使用何種方式指派。

繼續閱讀