[敏捷开发实践] 为什么开发人员不愿意写单元测试?
为什么开发人员不愿意写单元测试?
单元测试是专业开发人员确保真正完成编程任务的有效手段之一。但是实际开发中,绝大多数开发人员却非常抵触写单元测试,这又是很残酷的现实。开发人员有100个理由不写单元测试。我观察了超过20个项目的实际开发过程,与项目经理交谈,与开发者交谈后,也很理解在项目开发过程中他们所面临的“囧境”。也许你会反驳我:“这是不可能吧,连学习软件工程专业的大学生都知道编码完成之后,要写单元测试来验证程序是否按照预期的想法工作……”,“这是什么水平的码农,难道他们不知道TDD吗……难道他们不重视测试吗,他们不使用自动化测试吗……”,“他们是敏捷开发吗……没有单元测试,怎么适应快速迭代,构建应用,快速交付……”。没错,你懂得这些人都懂,甚至比还懂得多,这其中有入行三五年的开发者,也有入行超过二十年的“老老鸟”,但是现实就是,他们很少在项目中写单元测试。这就是残酷的现实。
总结以下,开发人员为什么不写单元测试?从很多次的项目回顾会议中抽取了一些典型的“不写单元测试的理由”,画一张图来说明吧。可以大概分为:认知、项目管理、技术三方面的原因:
其实,从上面的图中可以看出,对单元测试的认知层面的理由要多一些,这其实就是“明知故犯”。
开发者关注和重视的是新技术的应用,算法的优化,架构的“优良”等等,但是其实连最基本需要做的单元测试都不做。“单元测试只能增加我们的工作量,又没有什么实际的效果;后面不是还有测试团队吗?测试缺陷后,再修改吧~”
PM关心的是项目的进度和交付的Deadline,一大堆需要写的文档都还没写呢,再别说单元测试了。“我们玩的是敏捷开发,敏捷本来就是少文档呀,能不写就不写了……” (在我的另外一篇博客中,会谈到敏捷开发到底需要写哪些文档这个话题)
高层管理者关注的是项目是否能够按期交付和发布,至于单元测试那是项目经理和开发者的事情,再不行让QA去管理。但是到底质量为什么会出问题,发布后为什么缺陷很多,很少有人会把原因归结到“开发者没有写单元测试”,或者“单元测试覆盖率低”这样的原因上。即使有人提出了这样的问题,也会被大家哄笑而对:“你是做老师的吧,理论很扎实,但是项目实践太少……”。
哎,果真如此吗?
为什么要写单元测试
同样,放一张图来说明,为什么需要单元测试的基本理由:
写单元测试的好处
再讲这个话题之前,我与软件经理和开发者分别交谈,不同的场合中的交谈。我提到了一个问题:“什么是可测试性?”几乎没有人能够准确的回答这个问题。我同样也希望能够读到这篇博客的开发者考虑这个问题。
本质上说:一个功能如果是不可测试的,那么它也不会被测试。缺陷就隐藏在其中了。
创建单元测试是为了:
- 推动更好的设计
- 纠正代码中的错误,尽早的发现缺陷
- 规范编码和规范开发者的开发行为(习惯)
- 支持变化
- 避免回归缺陷
- 运行可扩展性
- 节省测试时间
- 提供工作的稳定节奏
- ……
良好的单元测试是自动化执行的,可自我验证的,可重复执行的,一致的和快速的。
一个单元测试用例只测试一个单一逻辑,并独立运行。
其实,无论开发者技术经验多么好,项目管理多么好,开发流程多么好,新技术、新框架都引入并采用了,TDD、FDD、ATDD等概念层面讲的多么头头是道,单元测试始终都是绕不过去的一道坎。为什么不能在如何写好单元测试,利用有效的单元测试工具提高单元测试的实践和通过率、自动化率方面好好思考呢?
软件产品的质量和测试的代价其实在一开始就注定了,在没有良好的单元测试的情况下就已经产生了危机。
认同的点个赞,不认同的看过笑笑就飘过……
分析数据不便于提供,但是结论已经不言而喻了……
单元测试和集成测试工具
作为一名开发者,你了解或者知道的单元测试工具和集成测试工具有多少呢?
工具名称 | 资源URL | 特点 |
---|---|---|
JUnit | https://junit.org/junit5/ | JUnit 5目标是为JVM开发人员开发一个最新的基础测试。这包括关注Java 8和更高版本,以及支持多种不同风格的测试。 |
REST Assured | http://rest-assured.io/ | 简约的接口测试DSL 支持xml json的结构化解析 支持xpath jsonpath gpath等多种解析方式 对spring的支持比较全面 |
Selenium | https://www.selenium.dev/ | Selenium也是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE、Mozilla Firefox、Mozilla Suite等。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。 |
TestNG | http://maven.apache.org/surefire/maven-surefire-plugin/examples/testng.html | TestNG是Java中的一个测试框架, 类似于JUnit 和NUnit, 功能都差不多, 只是功能更加强大,使用也更方便。 |
Mockito | Mockito是GitHub上使用最广泛的Mock框架,并与JUnit结合使用Mockito框架可以创建和配置mock对象。使用Mockito简化了具有外部依赖的类的测试开发。 | |
Spock Framework | http://spock-framework.3207229.n2.nabble.com/ | Spock是一个为Groovy和Java语言应用程序来测试和规范的框架。这个框架的突出点在于它美妙和高效表达规范的语言。得益于JUnit Runner,Spock能够在大多数IDE、编译工具、持续集成服务下工作。Spock的灵感源于JUnit,JMock, RSpec, Groovy,,Scala,,Vulcans以及其他优秀的框架形态。 |
Cucumber | https://cucumber.io/ | Cucumber是一个支持BDD(Behavior Driven Development),即行为驱动开发的自动化测试框架。在进行单元测试或者集成测试之前,事先将测试的步骤和验证信息用通用的语言(英语)定义好,使得测试的步骤、单元测试和集成测试每一步执行的目的能被非开发人员读懂,并且写单元测试和集成测试的人员可以依据事先写好的框架进行代码的编写,达到行为驱动开发的目的。 |
Spring Test |
Spring Test是Spring MVC自带了一个非常有用的测试框架,该框架无需进行Web容器即可进行深度测试。 在Spring的框架下,做单元测试使用spring中对Junit框架的整合功能 |
|
DBUnit | http://dbunit.sourceforge.net/ | DBUnit是一个基于Junit扩展的数据库测试框架。它提供了大量的类对与数据库相关的操作进行了抽象和封装,虽然在80%的情况,你只需使用它极少的api。它通过使用用户自定义的数据集以及相关操作使数据库处于一种可知的状态,从而使得测试自动化、可重复和相对独立。 |
Robot Framework | https://robotframework.org/ | Robot Framework是一个基于Python的,可扩展的关键字驱动的测试自动化框架,用于端到端验收测试和验收测试驱动开发(ATDD)。它可用于测试分布式异构应用程序,其中验证需要涉及多种技术和接口。 |
Httpunit | http://www.httpunit.org/ |
HttpUnit是一个开源的测试工具,是基于JUnit的一个测试框架,主要关注于测试Web应用,解决使用JUnit框架无法对远程Web内容进行测试的弊端。HttpUnit提供的帮助类让测试者可以通过Java类和服务器进行交互,并且将服务器端的响应当作文本或者DOM对象进行处理。
HttpUnit用Java编写,它模拟浏览器行为的相关部分,包括表单提交、JavaScript、基本http身份验证、cookies和自动页面重定向,并允许Java测试代码以文本、XML DOM或表单、表和链接的容器的形式检查返回的页面。当与JUnit这样的框架结合时,编写能够非常快速地验证web站点功能的测试是相当容易的。 |
NoSQLUnit | https://www.oschina.net/p/nosqlunit |
NoSQL的单元测试工具 授权协议:Apache 开发语言:Java 操作系统:跨平台 NoSQLUnit 是一个 JUnit 的扩展,用来为那些使用了 NoSQL 后端的应用提供单元测试和集成测试的工具。 |
JsTestDriver | https://www.oschina.net/p/jstestdriver |
JavaScript单元测试工具 授权协议:Apache 开发语言:JavaScript 操作系统:跨平台 JsTestDriver是一个JavaScript单元测试工具,易于与持续构建系统相集成并能够在多个浏览器上运行测试轻松实现TDD风格的开发。当在项目中配置好js-test-driver以后,如同junit测试java文件一般,js-test-driver可以直接通过直接运行js文件,来对js文件单元测试。 |
Venus |
JavaScript 单元测试工具 授权协议:Apache 2.0 开发语言:JavaScript 操作系统:跨平台 开发厂商:Linkedin Venus 是一个 JavaScript (JS)的测试工具,可以简化运行单元测试。当你在 JS 开发一个基于浏览器的项目时,你想创建单元测试并频繁地运行它们。通常,你会用一些库比如 Mocha 或 Jasmine,写一个单元测试,这些库可以让你定义测试用例,并提供 API 来编写判断。 通过创建一个工具,可以让你更轻松地与现有的库一起工作。一下是 Venus 的主要好处: 在你的测试使用 Simple annotations, 来指定你要使用的测试库,你要测试的文件,其它文件依赖,以及测试工具模板 |
|
Fluint |
Flex 单元测试工具 授权协议:MIT 开发语言:ActionScript 操作系统:跨平台 Fluint是一个 Flex 单元测试工具,对于Flex单元和集成测试,“Fluint”非常简洁。它是为编写Flex2或Flex3应用的开发者提供的测试框架,无论这些应用是通过Adobe Flash Player在浏览器中部署的,还是通过Adobe AIR在桌面上部署的。 Fluint最初是作为Digital Primates的内部工具开发的,用以测试一些非常大的项目。随着Flex社区对其需求的不断增长,Digital Primates决定把其发布为一个开源项目。尽管针对Flex有其他的单元测试解决方案,按照Labriala的说法,Fluint仍填补了重要空白。 |
|
Buster.JS | https://www.oschina.net/p/buster-js/related |
JavaScript 单元测试工具 Buster.JS 授权协议:BSD 开发语言:JavaScript 查看源码» 操作系统:跨平台 Buster.JS 是 JavaScript 的单元测试工具包,** **浏览器测试工具包;**Buster.js 可以自动的在浏览器上测试,像 JsTestDriver ;QUnit 风格 静态 HTML 页面测试 ; 在一些不知名的浏览器上测试,像 PhantomJS 和 jsdom ; Node.js 测试工具包; 灵活; Buster.js 里面几乎含有所有的公共 API 。你可自己书写* 测试报告* 来自定义 buster 的输出(buster 里面已经有 xUnit XML, traditional dots, specification, tap, TeamCity ),也可以编写扩展其他测试框架(buster 里面已经有 buster-jstestdriver ),添加你自己的测试语法(xUnit 和 BDD); 更多相关信息请看 the overview 。 |
SQLUnit | https://sourceforge.net/projects/sqlunit/ |
存储过程单元测试工具 SQLUnit 授权协议:未知 开发语言:Java 操作系统:跨平台 SQLUnit是一个用于对存储过程进行单元测试的工具,其实也可以用于做针对数据库数据、性能的测试等,延续了xUnit家族的一贯特性和风格,只不过它的测试是以xml的方式来编写,但原则仍然和xUnit家族其他产品一样,强调的是输出和预期的比较,SQLUnit的文档比较的少。 |
Jest |
Jest,是由Facebook开发的单元测试框架,也是Vue推荐的测试运行器之一。Vue对它的评价是: Jest 是功能最全的测试运行器。它所需的配置是最少的,默认安装了 JSDOM,内置断言且命令行的用户体验非常好。不过你需要一个能够将单文件组件导入到测试中的预处理器。我们已经创建了 vue-jest 预处理器来处理最常见的单文件组件特性,但仍不是 vue-loader 100% 的功能。 Vue-test-utils在Vue和Jest之前提供了一个桥梁,暴露出一些接口,让我们更加方便的通过Jest为Vue应用编写单元测试。 |
|
Vue-test-utils | Vue-test-utils是Vue的官方的单元测试框架,它提供了一系列非常方便的工具,使我们更加轻松的为Vue构建的应用来编写单元测试。主流的 JavaScript 测试运行器有很多,但 Vue Test Utils 都能够支持。它是测试运行器无关的。 |