单测的心得体会

简介: 单测是规范的软件开发流程中的必不可少的环节之一。再伟大的程序员也难以避免自己不犯错,不写出有BUG的程序。单测就是用来检测BUG的。Java阵营中,JUnit和TestNG是两个知名的单测框架。不过,用Java写单测实在是很繁琐,mock各种参数需要大量时间,所以单测试往往被认为鸡肋,会耗费很多时间。最近实习的过程中遇到一些坑,发现养成一个良好的单测习惯对于系统化开发是很有必要的。

背景介绍:

目前开发的项目基本都是基于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()注入解决这个问题。得出结论使用何种方式注入就要使用何种方式赋值。

相关文章
|
Java 测试技术
Spock单测利器,用了都说好
参考Spock单元测试框架介绍以及在美团优选的实践最近发现了一种写法简洁高效,一个单测方法可以测试多组测试数据,且测试结果一目了然的单测框架Spock。Spock国外的测试框架,其设计灵感来自JUnit、Mockito、Groovy,可以用于Java和Groovy应用的测试。尽管Spock写单测,需要使用groovy语言,但是groovy语言是一种弱类型,写法超级简单,我也是零基础的groovy新
1024 0
Spock单测利器,用了都说好
|
9月前
|
安全 测试技术 API
测试策略该怎么写
测试策略该怎么写
160 0
|
设计模式 新零售 供应链
一文教会你如何写复杂业务代码
这两天在看零售通商品域的代码。面对零售通如此复杂的业务场景,如何在架构和代码层面进行应对,是一个新课题。针对该命题,我进行了比较细致的思考和研究。结合实际的业务场景,我沉淀了一套“如何写复杂业务代码”的方法论,在此分享给大家。
28697 1
一文教会你如何写复杂业务代码
|
测试技术 Windows
测试思想-测试设计 授客细说场景测试用例设计与实践
测试思想-测试设计 授客细说场景测试用例设计与实践
124 0
测试思想-测试设计 授客细说场景测试用例设计与实践
|
缓存 JavaScript 小程序
接手前同事代码,特别烂,各种BUG,看麻了。。。
接手前同事代码,特别烂,各种BUG,看麻了。。。
|
程序员
程序员如何做好代码重构?
代码重构重构就是在不改变软件系统外部行为的前提下,改善它的内部结构。重构不是重写,它们的区别你可以理解为,重构是修复代码,大框架不变。重写是扔掉原来的,重新设计框架。
230 0
程序员如何做好代码重构?
|
自然语言处理 Java 测试技术
告别祈祷式编程|单元测试在项目里的正确落地姿势
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Jav...
187 1
|
JSON Java 测试技术
谈一谈单元测试
写在前面对于我们开发人员来说,单元测试一定不会陌生,但在各种原因下会被忽视,尤其是在我接触到的项目中,提测阶段发现各种各样的问题,我觉得有必要聊一下单元测试。对于单元测试到底有没有存在的必要,这里不是我想要说的重点。有兴趣的可以去了解一下:【单元测试和TDD】【单元测试到底是什么】为了写而写的单元测试没什么价值,但一个好的单元测试带来的收益是非常客观的。问题是怎么去写好单元测试?怎么去驱动写好单元
675 0
谈一谈单元测试
|
Java 测试技术 程序员
单元测试经典三问:是什么,为什么,怎么做?
编写合格的单元测试可以说是 Java 程序员的基本功。 很多公司对但单测覆盖率都会有要求,通常要求在 60% 到 90% 不等。 但是很多同学对单元测试或多或少有一些抵触,对如何写出“标准”的单元测试代码存在疑问。 有些同学编写单元测试,纯粹是应付工作,完全起不到单测应该起到的作用。 本文解答单元测试的三个基本问题,即单元测试是什么,为什么编写单元测试,怎么编写单元测试?
856 0
单元测试经典三问:是什么,为什么,怎么做?
|
测试技术 程序员 API
从零开始搞基建(4)——单元测试
  单元测试有助于避免尴尬、耗时的错误,将测试作为安全网只是一部分,更大部分是将测试表达为代码的思考过程。   接下来的内容提炼自《单元测试的艺术(第2版)》和《有效的单元测试》两本书。

相关实验场景

更多