测试分类简介
要验证正在工作的软件,最简单的方法之一就是执行一次构建(即编译源代码并执行测试);因此,长时间运行的构建是降低开发人员生产力的一项因素,这一点也不令人吃惊。不得不等待那超长的构建过程完成,几乎没有什么比这更恼人的了。可与之相提并论的就是编码过程中遇到意外的蓝屏和重启,但我们至少能够很容易地对时间较长的构建做点什么。
长时间构建的原因几乎总是测试执行这个步骤(除非是有数百万的.java 文件)。此外,如果存在大量的设置步骤,例如配置数据库或是部署一个 EAR 文件,执行一个测试套件的总时间倾向于变长。所以,精心设计一个测试分类策略并按照规定的时间间隔运行分类有利于获得可管理的构建持续时间。
然而,分类测试要求我们定义具体的分类,即细化单元测试。单元测试就像一张三层饼的一片,另两片则是组件测试和系统测试。下一节分析了开发人员通常会编写的不同类型的测试,诸如单元测试、组件测试和系统测试。随后,它们将在TestNG中执行,并集成到一个Ant 构建脚本里。
单元测试定义
单元测试验证独立对象的行为;然而,由于类的耦合,单元测试也能验证相关对象的行为。例如,下面的单元测试验证了对象身份,它是在TestNG中实现的,只关注一个类型:PartOfSpeechEnum。
/**
* @testng.test
*/
public class PartOfSpeechEnumTest {
public void verifyNotEquals() throws Exception{
assert PartOfSpeechEnum.ADJECTIVE !=
PartOfSpeechEnum.NOUN: "NOUN == ADJECTIVE?";
}
public void verifyEquals() throws Exception{
assert PartOfSpeechEnum.ADJECTIVE ==
PartOfSpeechEnum.ADJECTIVE "ADJECTIVE != ADJECTIVE";
}
}
有些时候,一个单元测试会验证多个对象的行为。然而,这些对象很少有其他的外部依赖项。例如,下面的测试验证了两个对象:Dependency和DependencyFinder。
//imports removed...
public class DependencyFinderTest {
private DependencyFinder finder;
/**
* @testng.test
*/
public void verifyFindDependencies() throws Exception{
String targetClss = "test.com.sedona.frmwrk.dep.Finder";
Filter[] filtr = new Filter[] {
new RegexPackageFilter("java|org")};
Dependency[] deps =
finder.findDependencies(targetClss, filtr);
Assert.assertNotNull(deps, "deps was null");
Assert.assertEquals(deps.length, 5, "should be 5 large");
}
/**
* @testng.before-class = "true"
*/
protected void init() throws Exception {
this.finder = new DependencyFinder();
}
}
要牢记的一个要点就是:单元测试不依靠外部依赖项,如数据库。数据库会增加设置和运行测试的时间。单元测试没有配置成本(就时间来度量),运行它的资源消耗可忽略不计。
单元测试运行很快,所以只要运行了一次构建,就应该运行单元测试,包括在持续集成环境中也是如此。在持续集成环境中,如果源储存库(如CVS)发生变更,通常就要运行构建。