首页 / 软件开发 / JAVA / 用Jython构建JUnit测试包
用Jython构建JUnit测试包2011-02-04Michael NadelJUnit 测试框架被越来越多的开发小组所共同使用。归功于各种各样的测试装具模块,现在可以测试构成任何 Java 应用程序的几乎每一个组件。事实上,几乎整个二级市场似乎都是用围绕 Junit 建立的。包括 Cactus、jfcUnit、XMLUnit、DbUnit 和 HttpUnit 这样的装具模块都可以免费供开发人员用于测试应用程序。随着系统的复杂程度的增加,并且有这么多工具可供使用,没有什么理由不依靠单元测试。不过,开发人员不仅仅是程序员。我们与用户交互以修复 bug 并确定需求。我们参加会议并进行电话推销。我们完成一些(有时全部)质量保证功能。既然有这么多责任,希望尽可能自动化就是自然而然的了。因为好的团队(除了其他事情外)会进行大量测试,希望自动化不同的开发过程的人常常会对这一领域进行详细研究。自动化单元测试有许多种自动化所有项目测试用例的定位和执行的方法。一种解决方案是联合使用 Ant 的 junit 任务与嵌入的 fileset 任务。这样就可以包括和排除特定目录中的文件(基于文件名样式)。另一种选择是使用 Eclipse 的一个功能,它可以指定所有测试所在的和执行的目录。前一种选择提供了对运行的测试进行过滤的灵活性(并且由于它是一个纯粹的无头(headless)Java 应用程序,可以运行在几乎所有地方),后一种选择可以调试“动态”包。是否可以结合这两种方式的强大和灵活性?有了 Python 编程语言的 Java 平台实现 -- Jython,回答是响亮的“可以!”(如果不熟悉 Jython,应当在继续本文之前补充这方面知识,更多信息请参阅后面的 参考资料)。利用 Jython 的强大和优雅,可以维护一个定位文件系统、搜索匹配某种样式的类和动态编译 JUnit TestSuite 类的脚本。这个 TestSuite 类像所有其他静态定义的类一样,可以用喜爱的调试程序容易地调试。(在本文中使用的例子假定使用的是 Eclipse IDE,不过,我在这里描述的技术不用做很多修改就可以用于大多数其他 IDE。)在进行任何设计决定时,必须对所做的选择和决定的影响进行权衡。在这里,为了得到调试动态生成的测试包的能力,必须增加额外的复杂性。不过,这种复杂性被 Jython 自身所减轻了:Jython 经过很好测试并得到很好的支持,并且是开放源代码的。而且,Python 越来越成为面向对象的、平台独立的编程的事实上的标准。出于这两种原因,采用 Jython 的风险很少,特别是它提供了这样的好处:在创建和调试动态生成的 JUnit TestSuite 类方面具有无可匹敌的灵活性。如果是否采用 Jython 是主要的考虑,那么即使不使用它也可以在解决原来的问题方面有所进展。不使用 Jython 的话,可以用一个 Java Property 文件存储一组类、目录和包,以在包中加入或者排除测试。不过,如果选择使用 Jython,就可以利用整个 Python 语言和运行时来解决选择执行哪些测试的问题。Python 脚本比 Java Property 文件灵活得多,它只受限于您的想像力。利用 Jython 与 Java 平台的无缝集成可以创建静态定义的、然而是动态构建的 TestSuite 类。有大量关于 JUnit 的教程,不过还是看下面这两行代码作为复习。清单 1 是静态构建 TestSuite 类的一个例子(这个例子取自 JUnit: A Cook"s Tour,有关它和其他 JUnit 资源的链接请参阅 参考资料):清单 1.静态定义 TestSuitepublic static Test suite() {
return new TestSuite( MoneyTest.class );
}清单 1 表明 TestSuite 是由 Test 类的类实例组成的。这个装具模块完全利用了这一点。为了分析这个工具的代码,应从 参考资料中下载本文的示例 JAR 文件。这个文档包含两个文件:DynamicTestSuite.java 和 getalltests.py,前者是一个用 Phthon 脚本动态生成 TestSuite 的 JUnit 测试装具模块,后者是一个搜索匹配特定样式的文件的 Python 脚本。DynamicTestSuite.java 使用 getalltests.py 构建 TestSuite 。可以修改 getalltests.py 以更好地适合自己的项目的需要.了解测试装具模块代码是如何工作的?首先,指派 getalltests.py 获取一组要执行的 Test 类。然后,使用 Jython API 将这个列表从 Python 运行时环境中提取出来。然后使用 Java Reflection API 构建在表示 Test 类名的列表中的 String 对象的类实例。最后,用 JUnit API 将 Test 添加到 TestSuite 中。这四个库的相互配合可以实现您的目标:动态构建的 TestSuite 可以像静态定义的那样运行。看一下清单 2 中的 JUnit suite 清单。它是一个公开 public static TestSuite suite() 方法签名的 TestCase 。由 JUnit 框架调用的 suite() 方法调用 getTestSuite() , getTestSuite() 又调用 getClassNamesViaJython() 以获取一组 String 对象,其中每一个对象表示一个作为包的一部分的 TestCase 类。