public void testXSLTransformation() {
/* initialize the variables
(or do this in setUp if used in many tests) */
String processMePath = "/path/to/file.xml";
String stylesheetPath = "/path/to/stylesheet.xsl";
String outputFilePath = "/path/to/output.xml";
//do the work
Transform.main(new String[] {
processMePath,
stylesheetPath,
"-o", outputFilePath } );
//check the work
assertTrue(checkOutputFile(outputFilePath));
}
每一步都可以根据需要进行增减。这里声明的变量也可以简单地通过调用方法来赋值。预期输出的实现是由几个步骤组成。如果成功得到预期输出,有时可以省略检查步骤。
虽然这个模式简单且灵活可变,但是第二步必不可少。这个模板没有告诉我们寻找要测试代码的方法,也不能保证代码以方便测试的方式运行。这是个需要认真考虑的问题。
功能测试
通过确定执行程序功能的主要代码段,可以将测试建立在一个更有效的环境下。由于这些类提供了从系统外部进行测试的途径,所以也是代码的入口点。
因此,功能测试的整体目标就是确定一组可以访问系统功能的高层接口类。这些类的独立性越高越好。毕竟,如果能将类从环境中分离出来,测试起来会更加容易。
确定作为入口点的代码是一个简单的过程。在代码库中,通常有几个控制该库所有功能的入口点。这些外部类作为客户端代码,与库的中介对象将开发人员从复杂的代码分析中解脱出来。这些便是应当首先对其方法进行测试的类。
比如,Saxon有一小组类作为逻辑入口点提供对库的访问。通过对外部类进行编码操作,比如转换、设置和查询,客户端代码可以访问库的许多功能类,而无需考虑类的接口问题,甚至无需担心这些类是否存在。这些外部类用高层易用的接口提供一个简单的方式对系统功能进行测试,这正是一个优良的库的特征。
程序代码中的各个功能模块通常是各自独立的。在某些代码中,甚至可以认为这些模块各自对应不同的、可通过大量外部类访问的库。这些类查找高层接口的逻辑位置。插件结构通常都采用这种设计模式:每个插件程序都有一个可以有效执行内部代码全部功能的简单接口。
在一些非严格描述的系统中,通常有一个所有程序行为的中介点。在MVC架构中,这个中介类一般作为“控制器”,负责配置系统各部分的请求路由。整体系统的功能主要由这个控制器连接的类实现,因此,这些类是测试的主要对象。
比如在 Applet程序设计中,java.applet.Applet的派生类就是所有代码的中心处理单元。根据代码的分解程度,测试焦点可以放在Applet 子类或与其连接的类上。
连接各个模块的代码也是测试的主要对象。将应用程序请求转换为数据库查询的类,以及有相似功能的适配类是其次应该考虑的测试对象。
各种基于MVC(模式-视图-控制器)架构的组件可以用其它的测试框架(比如Junit的扩展)进行测试。例如,Struts的 action类就最好使用JUnit的扩展StrutsTestCase进行测试;服务器端的组件(如Servlets、JSP和EJB)最好用 Catus进行测试;而HttpUnit则是对Web应用程序进行黑盒测试的最好框架。本文讨论的所有技术都可应用于这些框架环境下的测试。
从用例到测试用例
每个入口点都必须与相应的用例匹配。某些情况下可以忽视这一步,因为类名的自记录可以实现自动匹配,比如 Saxon中的转换类可以实现XSL转换,查询类可以进行XQuery转换。
其它情况则要复杂得多。通常用例描述的功能只能以横切关注点的方式存在,不能用任何单独的类进行例证。只有几组类交互时或满足一定条件时,才能观察到功能行为。这种情况下,测试的初始化程序会比较长,或者可以用 setUp()方法提供需要的测试环境。
而调用代码的运行程序应该尽可能地设计成一行,以减少与被测试代码的关联,这可以有效避免对边缘效应与不稳定实现细节的依赖。测试的检查阶段是最复杂的,因为这个阶段经常需要添写非测试用代码。测试时可能需要对结果进行严格的分析以确保其符合要求。有时甚至需要将这个过程分为几步来完成,以取得测试可以识别的结果。在XSL转换中,这两种情况都是可能的,结果储存在文件中,然后以XML格式读入内存并进行准确性分析。
原文转自:http://www.uml.org.cn/Test/20111142.asp