你真的会写单测吗?TDD初体验
前言:
昨天读到了一篇文章,讲的是TDD,即Test-Driven Development,测试驱动开发。大体意思是,它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并加速开发过程。
初读之时,瞬间感受到了震撼,感觉和自己之前的开发流程全都不一样,之前是由始至终,而这种思想确实以终为始。后来一查这种思想早在前几年甚至前几十年就被提出了,进而被广泛运用到了敏捷开发中。看来是自己孤落寡闻了,于是我准备将这种思想用到今后的开发中,要做的第一件事,就是温习如何写用例。
为什么是温习?
早在实习的时候,我们研发组就有写用例的习惯,但是随着开发逐渐熟悉,这种习惯不知不觉就被丢弃了,有页面的点点点,没页面的看逻辑。相信有很多人也像我一样,不知不觉就把这项技能丢弃了,接下来就让我们一起,去重新捡起这项技能。
工具选择
Junit
对于一个Java开发工程师来说,一提到写单测,我们最先想到的,一定是Junit。下面是maven坐标
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
用Junit我们可以快速的,简洁的用注解进行单元测试。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:conf/core/*.xml")
public class ObjTest { @Test
public void testFunc(){
//todo test
}
}
这里要注意的是@ContextConfiguration注解中的路径是Spring配置文件的位置。测试的方法必须是public的,且没有返回值。
mockito
mockito是一个用于模拟对象的工具,我认为他也是测试工作中必不可少的一部分,详细的介绍我推荐可以看一下:
人生苦短,我用Mockito https://zhuanlan.zhihu.com/p/59275373
比较不错的入门案例,它的maven坐标地址为:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
Mock这种测试方法, 对比传统的Junit测试,有如下好处:
- 不用每次测试的是时候,都初始化Spring容器,采用Mock的方式模拟对象,效率高
- 对象间的依赖关系,可以用Mock去表达,同时,我们不关心的部分,我们都可以用Mock的方式代替(比如对象A引用对象B的某某方法,但是我们不关系对象B方法实现,只想借助方法,这个时候就可以Mock)
- 可以应对复杂的测试环境,比如方法调用顺序、方法调用次数等等。
以下是Mock的一个小案例:
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
/**
* mock对象
*/
@Mock
List<String> mockedList; @Before
public void setUp() {
MockitoAnnotations.initMocks(this);
} @Test
public void testMock() {
// mock对象行为
Mockito.when(mockedList.get(0)).thenReturn("one");
Assert.assertEquals("one", mockedList.get(0));
// 仅仅是mock了对象的行为,实际上列表还是空的
Assert.assertEquals(0, mockedList.size()); //验证mock对象的get方法被调用过,且调用时的参数是0
Mockito.verify(mockedList).get(0);
}
}
这里在使用@Mock的时候,必须事先调用MockitoAnnotations.initMocks(this),且使用@RunWith(MockitoJUnitRunner.class)
Jacoco
JaCoCo是一个开源的覆盖率工具,支持多种覆盖率的统计,其中包括:
- 行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。
- 类覆盖率:度量计算class类文件是否被执行。
- 分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的总分支数,确定执行和不执行的 分支数量。
- 方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。
- 指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。
- 圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目,缺失的复杂度同样表示测 试案例没有完全覆盖到这个模块。
下面是它的maven坐标:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
接下来我们用maven插件的方式,对jacoco进行配置
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<configuration>
<includes>
<include>com/**/*</include>
</includes>
<!-- rules裏面指定覆蓋規則 -->
<rules>
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>BUNDLE</element>
<limits>
<!-- 指定方法覆蓋到50% -->
<limit implementation="org.jacoco.report.check.Limit">
<counter>METHOD</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
<!-- 指定分支覆蓋到50% -->
<limit implementation="org.jacoco.report.check.Limit">
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
<!-- 指定類覆蓋到100%,不能遺失任何類 -->
<limit implementation="org.jacoco.report.check.Limit">
<counter>CLASS</counter>
<value>MISSEDCOUNT</value>
<maximum>0</maximum>
</limit>
</limits>
</rule>
</rules>
</configuration>
<executions>
<execution>
<id>pre-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>post-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
这里值得注意的是<include>com/**/*</include>指的是class文件的位置。做完这些以后,我们就可以生成报表了。因为我们是用maven插件的方式进行配置的,所以如果我们使用idea进行开发的时候,就可以看到右侧maven一栏中出现了jacoco插件

最常用的就是这两个,一个是检查配置是否正确,第二个是用来将exec文件,生成index.html用来进行观察覆盖率。
我们先执行maven中的test指令,这时,我们在target中就可以看到一个jacoco.exec文件。

有了这个jacoco.exec文件,就可以使用jacoco的report方法,来生成文件。

右键index.html文件,选择Reveal in Finder(Mac),windows也是类似,打开文件磁盘的位置。


可以看到,由于这个项目之前没有几个单测,所以覆盖率特别低。点开之后,就可以看到具体的代码,非常的方便。

最后今天配置jacoco的时候,踩了2个坑:
1 用idea进行开发的同学。使用jacoco的时候,不要勾选这个按钮,它会跳过你测试阶段的代码执行,进而不会生成jacoco.exec文件。

2 保证自己测试代码没有错误(尤其是项目中,由于代码更新,测试用例没有更新,导致的测试不可用)
这里的现象是虽然可以生成jacoco.exec 文件,而且可以report成文档,但是打开之后发现,代码覆盖率都是0。
最后:
希望大家都可以保持写测试用例的好习惯,谢谢
你真的会写单测吗?TDD初体验的更多相关文章
- Python+Flask+Gunicorn 项目实战(一) 从零开始,写一个Markdown解析器 —— 初体验
(一)前言 在开始学习之前,你需要确保你对Python, JavaScript, HTML, Markdown语法有非常基础的了解.项目的源码你可以在 https://github.com/zhu-y ...
- 【阿里云产品公测】OpenSearch初体验
OpenSearch是一个非常有意义的功能,对于很多数据量较大的站点, SF2< 如果搜索功能自己做的话,或者用数据库里的查询语句,首先效率低下,而且占用资源. ); <Le6 另 ...
- 使用Groovy+Spock轻松写出更简洁的单测
当无法避免做一件事时,那就让它变得更简单. 概述 单测是规范的软件开发流程中的必不可少的环节之一.再伟大的程序员也难以避免自己不犯错,不写出有BUG的程序.单测就是用来检测BUG的.Java阵营中,J ...
- 使用Java函数接口及lambda表达式隔离和模拟外部依赖更容易滴单测
概述 单测是提升软件质量的有力手段.然而,由于编程语言上的支持不力,以及一些不好的编程习惯,导致编写单测很困难. 最容易理解最容易编写的单测,莫过于独立函数的单测.所谓独立函数,就是只依赖于传入的参数 ...
- 一分钟了解ruby中的单测
之前用gtest写过很多c++的单测case, 对gtest的强大和灵活印象深刻:最近需要用ruby写一个小工具, 接触了下ruby, 写了代码就要写单测啊(好的单测确实对代码的健壮性和正确性保证上太 ...
- 【spock】单测竟然可以如此丝滑
0. 为什么人人都讨厌写单测 在之前的关于swagger文章里提到过,程序员最讨厌的两件事,一件是别人不写文档,另一件就是自己写文档.这里如果把文档换成单元测试也同样成立. 每个开发人员都明白单元测试 ...
- 你真的会写单例模式吗-------Java实现
转载: 你真的会写单例模式吗--Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式,还真得费一番脑筋.本文对Java中常见的单例模式写法做了一个总结,如有错漏 ...
- [转] 你真的会写单例模式吗——Java实现
你真的会写单例模式吗——Java实现 原文:http://www.tuicool.com/articles/MBrUfy6 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模 ...
- 输入输出无依赖型函数的GroovySpock单测模板的自动生成工具(上)
目标 在<使用Groovy+Spock轻松写出更简洁的单测> 一文中,讲解了如何使用 Groovy + Spock 写出简洁易懂的单测. 对于相对简单的无外部服务依赖型函数,通常可以使用 ...
随机推荐
- Git版本控制之ubuntu搭建Git服务器
Git是一个开源的分布式版本控制系统,可以有效.高效的处理从很小到非常大的项目版本管理.使得开发者可以通过克隆(git clone),在本地机器上拷贝一个完整的Git仓库,也可以将代码提交到Git服务 ...
- Maven项目下使用log4j
Apache Log4j是一个基于Java的日志记录工具,它的日志级别按下面顺序递减: 级别 描述 OFF 最高级别,用于关闭日志记录. FATAL 将导致应用程序提前终止的严重错误的信息将立即呈现在 ...
- CS184.1X 计算机图形学导论 作业0
1.框架下载 在网站上下载了VS2012版本的作业0的框架,由于我的电脑上的VS是2017版的,根据提示安装好C++的版本,并框架的解决方案 重定解决方案目标为2017版本. 点击运行,可以出来界面. ...
- 告诉你如何回答"线上CPU100%排查"面试问题
不知道在大家面试中,有没有遇到这个问题: 生产服务器上部署了几个java程序,突然出现了CPU100%的异常告警,你如何定位出问题呢? 这个问题分为两版回答!高调版对不起,我是做研发的,这个问题在生产 ...
- wireshark分析https
0x01 分析淘宝网站的https数据流 打开淘宝 wireshark抓取到如下 第一部分: 因为https是基于http协议上的,可以看到首先也是和http协议一样的常规的TCP三次握手的连接建立, ...
- 高精度运算略解 在struct中重载运算符
高精度 高精度,即高精度算法,属于处理大数字的数学计算方法.在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字. 重载运算符 运算符重载,就是对已有的运算符重新进行 ...
- Redis启动报错解决
报错 redis_6379.service - LSB: start and stop redis_6379 Loaded: loaded (/etc/rc.d/init.d/redis_637 ...
- LeetCode 84--柱状图中最大的矩形( Largest Rectangle in Histogram) 85--最大矩形(Maximal Rectangle)
84题和85五题 基本是一样的,先说84题 84--柱状图中最大的矩形( Largest Rectangle in Histogram) 思路很简单,通过循环,分别判断第 i 个柱子能够延展的长度le ...
- JVM学习记录2--垃圾回收算法
首先要明确,垃圾回收管理jvm的堆内存,方法区是堆内存的一部分,所以也是. 而本地方法栈,虚拟机栈,程序计数器随着线程开始而产生,线程的结束而消亡,是不需要垃圾回收的. 1. 判断对象是否可以被回收 ...
- js数据交互——fetch
什么是fetch? Fetch被称为下一代Ajax技术,采用Promise方式来处理数据. 是一种简洁明了的API,比XMLHttpRequest更加简单易用.fetch是原生的(无需引入任何库和框架 ...