单元测试是为了驱动开发,重构设计,提高代码质量,不能无谓的追求测试覆盖率,对于难以测试的场景,需要根据各个项目因素(投入/产出)进行适当的裁剪。
多个方法可能组成一个行为,一个方法可能包含多个行为,如果一个方法可以用来做多种用途,可能根据参数的不同会有不同的表现,每种表现都是一种行为,有时多个方法组成一个行为,附带的方法只会在该主方法中使用,即可只测试主方法
私有方法是否需要进行测试:
私有方法一般不好进行测试,对于不是很复杂的私有方法,因为必然被其他公有方法进行调用,一般可以不进行测试。如果私有方法很复杂或者很难通过公开方法全面测试,则可以通过使用反射进行测试。
2.使用“Too Simple to Break” 规则
尽管在测试集中维持高代码覆盖率是很重要的,但是争取100%的覆盖率是不明智的。要考虑收益递减的观点。一个好的经验是如果一个方法简单到无法分割,就不用写单元测试了。关于什么是“简单到无法分割”还取决于解释,但是,为下面的方法写一个单元测试是没有什么用的:
|
简单的存取方法的测试是不可取的。
测试工作是一项非常耗时的工作,它节省的是未来的时间, 因此请确保你的测试是有效的。好的测试应该针对每个模块的核心功能,而不是事无巨细挨个测试。应该针对软件系统的行为来编写测试代码。你不需要面面俱到;为现在想到的东西先创建测试,然后想到别的再回来增加更多测试。
把测试用例整理出头等代码资产是很重要的。 你应该使用和你写产品代码一样的设计写测试用例。这意味着你应该找机会重构你的测试用例,把通用功能提升到基类,移除重复代码,分解长方法等等。无法做到这点将导致变更的花费,随着时间的流逝,导致测试集无效,此观点需说明的事,需按照项目的实际情况而定,对于时间较短项目,单元测试中大量的复制粘贴,冗余代码是可接受的。
这个看起来很显然,但是经常可以看到类似下面的测试方法:
|
|
取而代之应该是使用那些能够清晰描述测试目的的方法名称。这样做是的你的测试用例更好理解,更容易被维护。比如:
测试的成功或者失败不应该以开发者目测控制台来决定结果为基础。这意味着你不应该使用System.out.println() 或者 Logger.debug() 语句来决定你的测试的成功状态。取而代之的是你应该仅依赖JUnit的各种assertXXX() 方法,因此测试可以在无人照看、自动化方式下运行。
通常很难衡量你的测试用例在检查一个段代码时候有多完备。无法完整测试所有的执行路径可能导致你忽略一个严重的可能导致系统失败的应用bug,覆盖率工具可以成为你的Ant或者Maven编译过程的一部分,它们会生成可视的覆盖率报告显示你哪些行被测试了,不应盲目的追求100%的代码覆盖率,即便是100%的测试覆盖率也不能保证完全覆盖,另外盲目追求过高的代码覆盖率,投入/产出比将会降低。
这里有一些开源的工具可以达到这个目的:
Cobertura
Emma
EclEmma
JUnit提供了一个Java环境下的单元测试实体框架。但是仅仅JUnit无法保证你有效的测试你代码的全部功能。找到合适的工具很重要。幸运的是社区已经开发很多JUnit的扩展,它们将帮你测试你可能遇到的各种虚拟场景。
在测试不同的场景中可以使用使用不同的测试工具,下面会介绍这些工具。
-
- 自动化测试
通过junit与ant结合,通过一定的命名规则,自动执行单元测试代码,并生成一系列报告。对于使用maven的项目,可以通过使用maven-surefire-plugin插件进行自动化测试,及其方便。