Write Eclipse JUnit Tests in Jython

he Python language has a few characteristics that make it great for unit testing:

  • It integrates very well with the platform it runs on, so you can write tests that will run on every platform. For example, Jython integrates Python and Java; the Win32 extension fully integrates Python into COM objects, and so on. For large organizations, this flexibility in a single language saves a lot of time.
  • Python now has several testing paradigms and some great tools to perform the tests. To my mind, the most effective is to put the tests inside code comments (“doctests”), but this article focuses on another one: unittest, which is very close to JUnit from the Java space.
  • Python is quite straightforward because of dynamic typing (variables accept any type) and natural introspection. Coding in Python requires very few lines of code, and you don’t need to catch any specific exceptions. On top of that, you can write your tests before you code, because your testing code is not linked to your tested code. You can even make your tests part of your specifications if you really want to, which is not as easy to do so with compiled languages.

JUnit is one of the best-known Java testing frameworks. Eclipse 3.0 actually integrates a JUnit plugin. I use the continuous testing plugin, which enables me to test the code against a JUnit set of tests each time it compiles.

This article explains how to write Jython tests in an Eclipse/JUnit/continuous testing programming environment. It demonstrates setting up an environment with a simple class to test through a JUnit test case, and then adding a Jython test case that you can integrate seamlessly into the Eclipse JUnit view.

Basic Settings
This section demonstrates how to test the following class (Click here to download the accompanying code):

package tested;/** * @author Ploix, Forgeot d'Arc * */public class MyTested {	public char aMethodWhichIsOk (){		String s = "ABCD";		return s.charAt(2);	}		public char aMethodThatFails (){		String s = "ABCD";		return s.charAt(5);	}}

First, build a test with JUnit and write it in Java. In Eclipse, create a new JUnit test case. If the JUnit jar file is not referenced in your project, Eclipse will propose to add it. Say yes!

 
Figure 1. The Project Properties

Now, build a regular JUnit test case, derived from junit.framework.TestCase. You should get something like this:

package tests;/*** @author Ploix, Forgeot d'Arc**/import tested.MyTested;import junit.framework.TestCase;public class MyJavaTesting extends TestCase {	private MyTested tested = null;	public void setUp() {		tested = new MyTested();	}	public void testTheOkMethod() {		tested.aMethodWhichIsOk();	}	public void testTheFailMethod() {		tested.aMethodThatFails();	}}
 
Figure 2. Result of the JUnit Tests

In your Eclipse project settings, point your continuous testing properties to the MyJavaTesting class (see Figure 1).

Eclipse immediately displays the result of your test in the JUnit view (see Figure 2).

Next, you can write other tests in Jython and integrate the Jython test results seamlessly inside the same view. To do that, first you need to have Jython installed. And you also need to add the Jython jar file to your Eclipse project. Find it in your project properties (see Figure 3).

 
Figure 3. The Project Properties, Showing the Referenced Jar

You can have a Jython plugin installed, which could be better. (I use the “Jython Development Tools” plugin.) Don’t forget to set its properties in the main Eclipse Properties (see Figure 4).

Once everything is set, you should write your Jython test. Say, for instance, the following is your Jython class:

import junit, unittestimport tested## @author Ploix, Forgeot d'Arc## inherit from the TestCase class from Java ## and also from the one from unittest from pythonclass PythonTestCase (junit.framework.TestCase, unittest.TestCase):    """Class designed to be played either by unittest from Python (Jython, in fact),     or from JUnit in Java. Please cut and paste this class, and create your own test    methods (the one beginning by "test". Then report to the samples in Java to     see how to reference them from JUnit them.     """     def __init__(self, name):         """        name is the name of the test (the method) to play        """        junit.framework.TestCase.__init__(self,name)        self.theTestFunction = getattr(self,name)            def setUp(self):        """called before each test."""        pass    def tearDown(self):        """called after each test."""        pass    def runTest(self):        """tells JUnit which test to run"""        self.theTestFunction()     def testOkInJython(self):         inst = tested.MyTested ()        inst.aMethodWhichIsOk ()            def testFailedInJython(self):         inst = tested.MyTested ()        inst.aMethodThatFails ()        
 
Figure 4. The Jython Plugin Properties

You can recognize many things from JUnit: the inheritance, the testXXX method names, the setUp, the tearDown, and so on. You also can see that the setUp and tearDown methods are important here. Usually, you will use them as well.

Also, your Jython class uses a multiple inheritance, as one class comes from Java and the other comes from Python. This is useful only if you need to start your tests from Jython alone also. Here, you don’t really need to inherit from unittest.TestCase.

The runTest (from JUnit) and __init__ (the constructor) are very important. The Java code uses them to run the test itself. Whenever you define your own Jython JUnit test case, you should have these methods implemented or inherited.

The problem becomes integrating this test into your JUnit tests.

Integrating the Jython Test
Integrating your Jython test in JUnit is very easy. It takes one line of Java code per Jython class. But to fully understand how to do it, consider the following steps you’ll take in this section:

  1. You use the “Suite” way to discover the tests under JUnit. JUnit can use a suite() method to get the tests to run. You just have to build a Suite that gives JUnit enough information to run the Jython tests.
  2. This suite() method is not as simple to use as it seems, for it is static. So you have to discover the Jython tests to insert in the suite before they are instantiated. You will use static blocks to extract the Jython tests.
  3. You make some introspection inside Jython, then get the Jython Suite and cast it into the Java space through useful classes.

The first class to use is a Jython Suite Extractor (JythonTestSuiteExtractor.java). It basically extracts the proper methods from your Jython class and adds them to a suite. Then the suite, built in a Jython interpreter, is converted into Java. You should not have to modify anything in it.

The second class (JythonTestCaseExtractor.java) is a bit trickier. It uses static calls and structures to store the Jython test cases that will have to be integrated into the suite. You won’t need to modify this class either.

The third class (MyJythonTestCase.java) just loads your Jython test case into the JythonTestCaseExtractor, in a static way. This class should be adapted to integrate your own Jython tests once you have new ones, as follows:

/* * Created on 1 Sept. 2004 * */package tests;import junit.framework.Test;import junit.framework.TestCase;import fr.sgf.tools.pyjunit.JythonTestCaseExtractor;/** * To use a python test case inside JUnit, you need to define a class that * implements two (horrible) things: a static block and a suite method. The * reason comes from the way JUnit works--I'm innocent ;-). So define a class * that extends TestCase: the static block should add the * Python tests with directory, module name, and class name. The suite block * should call JythonTestCaseExtractor.suite(), that's all. God, it was a mess. * Oh, and if you want to integrate it inside another Suite, you should call * suite.addTest(MyJythonTestCase.suite()), and not * suite.addTestSuite(MyJythonTestCase.class), which doesn't work. *  * @author Ploix, Forgeot d'Arc *  *   */public class MyJythonTestCase extends TestCase {    static {        JythonTestCaseExtractor.addPythonTest("bin/tests",                "JythonTestSuite", "PythonTestCase");    }     public static Test suite() {        return JythonTestCaseExtractor.suite();    }}

The static block adds the Jython class, considering the following factors:

  • The classes can be found in bin/tests directory of your project.
  • The class to add can be found in the JythonTestSuite module.
  • The Jython class itself is named PythonTestCase.

You could add as many “addPythonTest” calls to integrate as many test cases as you need. The previous snippet included only one. In any case, any method beginning with the word “test” in the Jython classes will be added.

Now, you have to tell JUnit that this Java class is the one that contains the JUnit tests. If you run this class as a JUnit test, the Jython tests will be used instead.

If you want to see your Java and your Jython tests in the same view, you have to integrate them in another suite. That’s easy. Just write a JUnit test case:

/* * Created on 20 August 2004 * @author Ploix, Forgeot d'Arc * */package tests;import junit.framework.Test;import junit.framework.TestCase;import junit.framework.TestSuite;/** * @author ploix *  */public class AllTests extends TestCase {    public static Test suite() {         TestSuite suite = new TestSuite("Tests in Java and in Jython");        suite.addTestSuite(MyJavaTesting.class);        suite.addTest(MyJythonTestCase.suite());        return suite;     }}
 
Figure 5. The Jython and Java Tests in the Same Window

The Jython wrapper (MyJythonTestCase) should be added with a call to the suite() method.

Your Eclipse JUnit plugin will see this class as if the Jython tests were written in Java (see Figure 5).

Once you have set it up, writing new Jython tests is very straightforward. You need to add one line of code to the MyJythonTestCase class and it works. New Jython methods integrate immediately and without any compilation steps. Jython and Java tests are started and their results are displayed in the same view.

Fast, Easy Unit Tests
Once these setup steps are done, you will find that writing unit tests with Jython is much faster and requires less code than with Java. The original goal of Python was to be a scripting language; Jython enables you to script your Java applications, and it eases the task of writing tests.

What’s Next?
This article demonstrated how to integrate Jython tests into Eclipse and its JUnit plugin. It could have shown how to integrate it into an Ant task, or any other tool that enables test running. That technology improves greatly the programmer’s productivity.

Now, wouldn’t enabling C-Python testing from the JUnit Eclipse framework be great? It would enable Eclipse to become an IDE with cross-language, on-the-fly testing integration. It’s not as difficult as it seems; it requires code generation, but that’s a topic for another article.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

The Latest

Top 5 B2B SaaS Marketing Agencies for 2023

In recent years, the software-as-a-service (SaaS) sector has experienced exponential growth as more and more companies choose cloud-based solutions. Any SaaS company hoping to stay ahead of the curve in this quickly changing industry needs to invest in effective marketing. So selecting the best marketing agency can mean the difference

technology leadership

Why the World Needs More Technology Leadership

As a fact, technology has touched every single aspect of our lives. And there are some technology giants in today’s world which have been frequently opined to have a strong influence on recent overall technological influence. Moreover, those tech giants have popular technology leaders leading the companies toward achieving greatness.

iOS app development

The Future of iOS App Development: Trends to Watch

When it launched in 2008, the Apple App Store only had 500 apps available. By the first quarter of 2022, the store had about 2.18 million iOS-exclusive apps. Average monthly app releases for the platform reached 34,000 in the first half of 2022, indicating rapid growth in iOS app development.