单测的心得体会

简介: 单测是规范的软件开发流程中的必不可少的环节之一。再伟大的程序员也难以避免自己不犯错,不写出有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"
    }
AI 代码解读

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', '', '']
    }
AI 代码解读

对于异常场景可以使用这种

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异常信息"]

    }
AI 代码解读

这边就是主要使用的三个例子,需要异常抛出的情况不能和正常情况一起使用。需要区分为两个测试方法。

遇到的坑:

今晚写一个单测,仿照项目中原先的老代码写的。对于代码中mock使用的是Mockito注解方式,发现使用注解方式可以获取到这个类但是对于使用grooy 语法进行方法调用赋值一直为null但是注入的类不为空否则会报NPE问题。后来通过重新使用mock()注入解决这个问题。得出结论使用何种方式注入就要使用何种方式赋值。

目录
打赏
0
0
0
1
1
分享
相关文章
Rockchip系列之CAN APP测试应用实现(4)
Rockchip系列之CAN APP测试应用实现(4)
268 1
后端技术在现代Web开发中的实践与创新
【10月更文挑战第13天】 本文将深入探讨后端技术在现代Web开发中的重要性,通过实际案例分析展示如何利用先进的后端技术提升用户体验和系统性能。我们将从基础架构设计、数据库优化、安全性保障等方面展开讨论,为读者提供清晰的指导和实用的技巧。无论是新手开发者还是经验丰富的技术人员,都能从中获得启发和帮助。
179 2
R语言VaR市场风险计算方法与回测、用LOGIT逻辑回归、PROBIT模型信用风险与分类模型
R语言VaR市场风险计算方法与回测、用LOGIT逻辑回归、PROBIT模型信用风险与分类模型
MyCAT----读写分离
MyCAT 是一款用 Java 开发的开源数据库中间件,需在 JDK7 以上环境运行。它位于应用与数据库间,负责数据处理与交互,支持读写分离与分库分表。部署时需先安装 JDK,再下载解压 MyCAT,并配置 `server.xml` 和 `schema.xml` 文件定义用户、逻辑库及数据节点。启动 MyCAT 后,可通过 SQL 客户端验证读写分离策略。
springboot 日志配置(logback)(二)
springboot 日志配置(logback)(二)
619 0
tailf报错limit of inotify watches was reached
tailf报错limit of inotify watches was reached
3673 0
Warning: [antd: Form.Item] `defaultValue` will not work on controlled Field. You should use `initialValues` of Form instead.
Warning: [antd: Form.Item] `defaultValue` will not work on controlled Field. You should use `initialValues` of Form instead.
1032 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问