Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » 技术文章库  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 Use Jython to build JUnit test suites(英文原文) [Re:palatum]
palatum



CJSDN高级会员


发贴: 451
积分: 80
于 2004-06-06 14:32 user profilesend a private message to usersend email to palatumsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Use Jython to build JUnit test suites

Python and Java technology work together to solve the impossible

Michael Nadel (mnadel@flywheelcorporation.com)
Java Developer, Chicago Technology Partners
11 May 2004

Developers decide to automate unit tests for a number of reasons. Many take it even a step further and automate the location and execution of those tests. But what if you need your test harness to act as if it were statically defined? Follow along with developer Michael Nadel and see how to use Python to feign statically defined JUnit TestSuite classes.
The JUnit testing framework is commonly used by an increasing number of development teams. Thanks to a myriad of testing harnesses, it's now possible to test almost every component comprising any type of Java application. In fact, it's almost as if an entire secondary market is forming around JUnit. Harnesses including Cactus, jfcUnit, XMLUnit, DbUnit, and HttpUnit are all freely available to developers for use in testing our applications. As systems' complexities increase, and with so many tools at our disposal, there's little reason to not rely on unit tests.

However, developers are more than just programmers. We interact with users to fix bugs and hammer out requirements. We go to meetings and go on sales calls. We perform some (and sometimes all) of the functions of quality assurance. With so many responsibilities, it is only natural to want to automate as much as possible. Because great teams (among other things) generate a lot of tests, this is an area that often comes under the scrutiny of those who seek to automate various development processes.

Automating unit tests
There are many ways to automate the location and execution of all a project's test cases. One solution is to use Ant's junit task in conjunction with a nested fileset task. This allows you to include and exclude files (based on filename patterns) under a specified directory. Another option is to use a feature of Eclipse with which you can specify a directory under which all tests are located and executed. The former option provides flexibility in filtering the tests that are run (and since it's a pure headless Java application, it can be run almost anywhere), and the latter option allows you to debug your "dynamic" suite. But can you combine the power and flexibility of these two approaches?

Thanks to Jython, a Java platform implementation of the Python programming language, the answer is a resounding "yes!" (If you're not familiar with Jython, you should brush up before going further in this article; see the links in the Resources section below for more information.) Using the power and elegance of Jython, you can maintain a script that scours your filesystem, searching for classes that match a certain pattern, and dynamically build a JUnit TestSuite class. This TestSuite class, like any other statically defined class, can be easily debugged using your favorite debugger. (The examples I'll use in this article will assume use of the Eclipse IDE; however, the techniques I describe here will work with most other IDEs without much modification.)

When making any design decisions, you must address the tradeoffs of your options and the impact of your decision. In this case, in order to gain the ability to debug dynamically generated test suites, you are forced to add additional complexity. The complexity, however, is mitigated by Jython itself: Jython is well tested and supported, and is open source. Furthermore, Python is increasingly becoming the de facto standard of object-oriented, platform-independent scripting. For these two reasons, there is little risk in adopting Jython, especially given the payoff: unparalleled flexibility in the creation and debugging of dynamically generated JUnit TestSuite classes.

If adopting Jython were a major concern, it'd be possible to nevertheless make headway on the original problem without it. Instead of using Jython, you could use a Java Property file to store a list of classes, directories, and packages to include or exclude tests from your suite. However, in choosing to use Jython, you are able to bring to bear the entire Python language and runtime against your problem of choosing which tests to execute. A Python script is so much more flexible than Java Property file that the possibilities are limited only by your imagination.

Exploiting Jython's seamless integration with the Java platform allows you to create a statically defined, yet dynamically constructed TestSuite class. Numerous tutorials on JUnit exist, but let's look at a two-line refresher. Listing 1 is an example of how TestSuite classes are statically constructed (this example comes from JUnit: A Cook's Tour; see Resources for a link to this and other JUnit resources):

Listing 1. Statically defining a TestSuite

public static Test suite() {
return new TestSuite( MoneyTest.class );
}



Listing 1 illustrates that a TestSuite is composed of class instances of Test classes. The harness fully takes advantage of this. To take a look at the harness code, download this article's sample JAR file from the Resources section. This archive contains two files: DynamicTestSuite.java, a JUnit test harness that dynamically generates a TestSuite using a Python script; and getalltests.py, a Python script that searches for files matching a specific pattern. DynamicTestSuite.java uses getalltests.py to build a TestSuite. You can modify getalltests.py to better match your project's needs.

A look at the test harness
How does the code work? First, you delegate to getalltests.py to retrieve a list of Test classes to execute. Next, you use the Jython API to extract that list out of the Python runtime environment. Then you use the Java Reflection API to construct class instances of the String objects in your list that represent Test class names. Finally, you turn to the JUnit API to add the Test to your TestSuite. It is the interoperation of these four libraries that allows you to achieve your goal: a dynamically constructed TestSuite that acts as if it were statically defined.

Take a look at the JUnit suite listing in Listing 2. It's a TestCase that exposes the public static TestSuite suite() method signature. The suite() method, which is called by the JUnit framework, calls getTestSuite(), which in turn calls getClassNamesViaJython() in order to retrieve a list of String objects, each representing a TestCase class that is part of the suite.

Listing 2. Dynamic defining a TestSuite

/**
* @return TestSuite A test suite containing all our tests (as found by Python script)
*/
private TestSuite getTestSuite() {
TestSuite suite = new TestSuite();

// get Iterator to class names we're going to add to our Suite
Iterator testClassNames = getClassNamesViaJython().iterator();

while( testClassNames.hasNext() ) {
String classname = testClassNames.next().toString();

try {
// construct a Class object given the test case class name
Class testClass = Class.forName( classname );

// add to our suite
suite.addTestSuite( testClass );

System.out.println( "Added: " + classname );
}
catch( ClassNotFoundException e ) {
StringBuffer warning = new StringBuffer();
warning.append( "Warning: Class '" ).append( classname ).append( "' not found." );
System.out.println( warning.toString() );
}
}

return suite;
}



At the outset, you ensure that the correct system property is set. Internally, Jython will use the python.home property to locate its required files. Eventually, the getClassNamesViaJython() method is invoked, which is where all the magic happens, as you'll see in Listing 3.

Listing 3. Extracting Java objects of the Python runtime

/**
* Get list of tests we're going to add to our suite
* @return List A List of String objects, each representing class name of a TestCase
*/
private List getClassNamesViaJython() {
// run python script
interpreter.execfile( getPathToScript() );

// extract out Python object named PYTHON_OBJECT_NAME
PyObject allTestsAsPythonObject = interpreter.get( PYTHON_OBJECT_NAME );

// convert the Python object to a String[]
String[] allTests = (String[]) allTestsAsPythonObject.__tojava__( String[].class );

// add all elements of array to a List
List testList = new ArrayList();
testList.addAll( Arrays.asList( allTests ) );

return testList;
}



First, the Python file is evaluated. Next, you extract a PyObject out of the Python runtime. This is the resulting object that contains the class names of all the test cases that will compose your suite. (Remember -- a PyObject is the Java runtime counterpart to a Python object.) Then you create a concrete List and populate it with the contents of the PyObject, using __tojava__ to instruct the PyObject to convert its contents to a Java String array. Finally, control is returned to getTestSuite(), where you load the test cases that Jython identified, and add them to the composite.

Install the test harness in your development environment
Now that you have a solid understanding of how the test harness works, you're probably eager to try it out yourself. You'll need to walk through the following steps to configure Eclipse to run the harness. (If you're using a different IDE, you should be able to easily adapt these steps for your environment.)

Install Jython 2.1 if you haven't already (see Resources for a link).

Copy getalltests.py to your home directory.

Edit line 25 of getalltests.py to specify the path to the root of your source; all directories under this location will be searched for filenames matching *Test.java within the org package.
If necessary, modify line 54 to change the root package name (to com, for example).

Copy DynamicTestSuite.java into your source tree.

Add the following JARs to your Eclipse project:
junit.jar (the JUnit framework binaries; see JUnit's Web site for download information).
jython.jar(Jython binaries; located in the Jython installation directory).

Load the DynamicTestSuite class into Eclipse's Java source editor. Follow one of the steps below:
Select DynamicTestSuite from the Package Explorer view, or;
Press Ctrl+Shift+T and type DynamicTestSuite into the Choose Type input field.

Select Run from the file menu bar, then Debug...

Select the JUnit configuration.

Click the New button. A new JUnit target will be created, and DynamicTestSuite should be pre-filled in the Test Class field.

Select the Arguments tab.

Type -Dpython.home=<path where you installed Jython> into the VM arguments text box.

Click the Debug button.
And presto! You now have a concrete JUnit TestCase class that can be treated as if the suite composite were statically defined. Set your breakpoints, and debug away! No modifications to your Test classes are needed; the harness constructs a suite as if you had explicitly coded each Class object into the suite. In order to execute your tests, the harness can be invoked through your favorite debugger, build tool (such as Ant or CruiseControl), or one of JUnit's included test runners.

Extending the harness
I'm sure you noticed that the harness will work only for a single project, unless you were to modify the source before running it. You could easily extend the harness to support multiple projects. One simple way is to modify getPathToScript() to use system properties that specify project-specific attributes. Feel free to use, either as-is or as a foundation, the harness in your own projects. Please, however, be mindful of its GPL license.




话题树型展开
人气 标题 作者 字数 发贴时间
7675 用 Jython 构建 JUnit 测试包--摘自IBM DeveloperWorks palatum 6114 2004-06-06 14:30
6931 Use Jython to build JUnit test suites(英文原文) palatum 11843 2004-06-06 14:32

flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923