devxlogo

JUnit Testing Using Java ME JUnit Frameworks

JUnit Testing Using Java ME JUnit Frameworks

Unit tests have become a staple part of most Java Standard Edition (SE) and Enterprise Edition (EE) applications?especially those that espouse test-driven development. Kent Beck and Eric Gamma’s original Smalltalk framework has become so popular and successful that it has been ported to a wide variety of programming languages to include Ada (AUnit) C# (NUnit), Python (PyUnit), and even Fortran (fUnit). Arguably, Java’s JUnit has been the most successful of all unit testing frameworks and has generated many JUnit offspring, in the form of extensions, to help unit test everything from multi-threaded Java applications to high powered enterprise Java applications.

However, using JUnit or finding a JUnit extension for use in Java Micro Edition (ME) development has been a little tough. JUnit frameworks rely on Java reflection. Since the reflective API is not present in Java ME environments, typical JUnit tools, which rely heavily on reflection, do not help. In spite of this, there are two (soon to be one?more on this in a bit) Java ME JUnit extensions built especially for device application developers. Importantly, NetBeans and the NetBeans Mobility Pack plan on incorporating a Java ME JUnit-style framework with the release of NetBeans and NetBeans Mobility 5.5. The IDE provides a neat capability to add unit testing to your ME applications very quickly.

This article introduces you to JUnit testing using Java ME JUnit frameworks; where to find them, how to test with them, and how to use them to build better quality software.

Where to Get a Java ME Unit Test Framework
Today, there are two Java ME JUnit test frameworks available. They are J2MEUnit and JMUnit. Both projects are open source frameworks available in a single download file via SourceForge.net.

However, the project administrators of these two open source projects (Elmar Sonnenschein and Brunno Silva, respectively for J2MEUnit and JMUnit), plan to merge their two frameworks into one. The new project will be consolidated under the J2MEUnit project moniker. According to Sonnenschein, “because of the larger existing user base the resulting project will be hosted under the J2MEUnit name at SourceForge. We’re planning to create a J2MEUnit 2.0 release from Brunno’s JMUnit 2.0 codebase.” In a recent correspondence with Silva, he indicated that completion of the merged product and a 2.0 release will probably not be completed this year. Don’t let the merged project stymie plans to incorporate unit testing into your micro edition application. Silva further suggested that the projects did not “want to break the code of the current users of both frameworks, so the original code is going to be presented, but deprecated. The united framework shall bring features of both, JMUnit and J2MEUnit.”

A Simple Application
Before examining the various unit test frameworks, you will need some simple code to test. In this examination, the simple conversion classes below can be used to create and test Java ME unit tests.

public class DistanceConversion {  public static int feetToMeters(int ft){ return (ft * 3048)/10000; }  public static int metersToFeet(int meters){ return (meters*3281)/1000; }  public static int milesToKM(int miles){ return (miles*1609)/1000; }  public static int kmToMiles(int km){ return (km*6214)/10000; }}public class TemperatureConversion {  public static float fahrenheitToCelsius (float degrees){ return ((degrees-32)/9)*5; }  public static float celsiusToFahrenheit (float degrees){ return ((degrees * 9)/5)+32; }  public static boolean isHotter (float degFaren, float degCel){ return ((fahrenheitToCelsius(degFaren))-degCel) > 0; }  public static boolean isCooler (float degFaren, float degCel){ return ((fahrenheitToCelsius(degFaren))-degCel) 

Note that this code uses CLDC 1.1's floating point primitive type. In order for this code to execute in a CLDC 1.0 environment, the code would need to use integer primitives in place of float primitives as shown below. A copy of all the code and test classes for both CLDC 1.1 and CLDC 1.0 is provided in zip files with this article.

public class DistanceConversion {  public static int feetToMeters(int ft){ return (ft * 3048)/10000; }  public static int metersToFeet(int meters){ return (meters*3281)/1000; }  public static int milesToKM(int miles){ return (miles*1609)/1000; }  public static int kmToMiles(int km){ return (km*6214)/10000; }}public class TemperatureConversion {  public static int fahrenheitToCelsius (int degrees){ return ((degrees-32)/9)*5; }  public static int celsiusToFahrenheit (int degrees){ return ((degrees * 9)/5)+32; }  public static boolean isHotter (int degFaren, int degCel){ return ((fahrenheitToCelsius(degFaren))-degCel) > 0; }  public static boolean isCooler (int degFaren, int degCel){ return ((fahrenheitToCelsius(degFaren))-degCel) 

Working with JMUnit

Setting up JMUnit
After obtaining the JMUnit download, make sure that the two JMUnit .jar files (JMUnit4CLDC10.jar and JMUnit4CLDC11.jar) are available on the classpath for both your Java ME compiler and runtime environment or IDE. The current release of JMUnit is labeled 1.0.2.

JMUnit Test Cases
JMUnit provides two versions of the framework (each version is in its own JAR); one for use with CLDC 1.0 applications and another for CLDC 1.1 applications where floating point primitives are supported. In customary JUnit fashion, the first step to creating appropriate unit tests using JMUnit is to create a test case. To create a test case in JMUnit, you must create a new test case class that either extends JMUnit's jmunit.framework.cldc10.TestCase or jmunit.framework.cldc11.TestCase. As the package names suggest, one provides support for 1.0 and the other 1.1 versions of CLDC. The only difference is that the cldc11.TestCase implementation of assertEquals() and assertNotEquals() methods (see below) support Java floating-point primitives.

By JUnit convention, a test case class should contain the name of the class to test and end with "Test." Therefore, a JMUnit test case to test the simple CLDC 1.1 version of the temperature conversion class above would be defined like this:

public class TemperatureConversionTest extends jmunit.framework.cldc11.TestCase {}

All test methods must be in a test case class. Again, by convention, test method names begin with "test" and then are named after the methods in the class being tested. For example, a test case method to test the fahrenheitToCelsius method should be called testfahrenheitToCelsius. Each test method must "assert" expected results. For those not familiar with JUnit testing, an assertion is a statement which verifies or disproves a programmer's expected results from method execution. JMUnit supports the following assertions:

assertTrue(expression)assertFalse(expression)assertSame(expected,actual)assertNotSame(expected,actual)assertEquals(expected,actual)assertNotEquals(expected,actual)assertNull(object)assertNotNull(object)

In JMUnit, any test method that makes uses of one of these assertion calls must throwAssertionFailedException. The framework uses the exception to identify failed tests. The TemperatureConversionTest class with appropriate test methods would now look something like that listed below.

import jmunit.framework.cldc11.*;public class TemperatureConversionTest extends TestCase { public void testfahrenheitToCelsius() throws AssertionFailedException{   System.out.println("fahrenheitToCelsius");   float result = TemperatureConversion.fahrenheitToCelsius(66F);   assertEquals(18.88889F,result); } public void testcelsiusToFahrenheit() throws AssertionFailedException{   System.out.println("celsiusToFahrenheit");   float result = TemperatureConversion.celsiusToFahrenheit(20F);   assertEquals(68F, result); } public void testisHotter() throws AssertionFailedException {   System.out.println("isHotter");   assertTrue(TemperatureConversion.isHotter(70F,2F)); } public void testisCooler() throws AssertionFailedException {   System.out.println("isCooler");   assertTrue(TemperatureConversion.isCooler(10F,10F)); }}

Per standard JUnit implementation, JMUnit test case abstract classes also provide methods of setup() and tearDown() that can be overridden and used to initialize and then cleanup any objects or resources before and after tests run via the test case. For example, in Java ME applications, setup may be used to open a Record Store before testing and tearDown used to close the Record Store after testing. In addition to setup and tearDown, a fail() method allows a test method to return a test failure no matter what any assert statement indicates. This method is often used in some sort of conditional within a test method or it can be used to stub out undeveloped unit tests as a way of indicating work still to be done.

Test case classes in JMUnit come with a constructor. The constructor for your test case class that extends one of JMUnit's test case classes must call on the super constructor, passing in an integer indicating the number of tests in the test case and a string identifying the test case.

public TemperatureConversionTest() { super(4,"TemperatureConversionTest");}

The integer indicating the number of tests must match the number of actual tests in the test case. It is important to make sure the number of tests you pass into the constructor matches the actual number of tests in the test case. Its relevance shows up when you look at the test case's test(int testNumber) method.

The test(int testNumber) method in a test case kicks off the test methods. Again, because Java ME is without reflective capabilities, test methods cannot be found and executed automatically as in JUnit. So each test method must be added to a switch statement in the test method and invoked based on a test number. In the case of the TemperatureConversionTest, the test method would look like code below:

 public void test(int testNumber) throws Throwable {   switch(testNumber) {     case 0:testfahrenheitToCelsius();break;     case 1:testcelsiusToFahrenheit();break;     case 2:testisHotter();break;     case 3:testisCooler();break;     default: break;   } }

This is the reason why you must provide the number of tests to the test case constructor. At runtime, the JMUnit framework creates an instance of the test case class. The framework invokes each test method of the test case instance in a loop, starting from 0 to one less than the number of tests indicated via the constructor. In this way, each case of the test method's switch statement (and therefore each unit test) gets invoked by the framework. Forgetting to update the test case class constructor when adding a test method to the test case will result in not all the test cases firing.

Because you write the test method, JMUnit differs from, and is perhaps more flexible, than JUnit in the way it allows test methods to execute. With control of the test method, you can write tests that take parameters?something JUnit does not allow (because of reflection). For example, a test method for TemperatureConverstionTest might look like the following:

public void testcelsiusToFahrenheit(float c, float f) throws AssertionFailedException{ System.out.println("celsiusToFahrenheit(float c)"); float result = TemperatureConversion.celsiusToFahrenheit(c); assertEquals(f, result);}

The test method can then use parameters to call on this test method in the switch statement.

public void test(int testNumber) throws Throwable { switch(testNumber) {   case 0:testfahrenheitToCelsius();break;   case 1:testcelsiusToFahrenheit();break;   case 2:testisHotter();break;   case 3:testisCooler();break;   case 4:testcelsiusToFahrenheit(20F,68F);break;   default: break; }}

Figure 1. Executing a Test Case: Executing a JMUnit test suite offers you the option to exit or test the suite. Results of the test suite are shown graphically.
 
Figure 2. A Failure Test Case: Failure shows up graphically in red when a test case fails.

JMUnit TestSuite
Test suites manage one or more test cases. JMUnit provides two test suite abstract classes (jmunit.framework.cldc10.TestSuite and jmunit.framework.cldc11.TestSuite) which you extend to create a test suite. Again, as with test cases, the type of test suite you should extend depends on which version of CLDC you are using. Use cldc10.TestSuite for CLDC 1.0 applications and use cldc11.TestSuite for CLDC 1.1 applications. Both test suite abstract classes have a constructor that takes a string as a parameter. The string gives the suite a description.

A test suite's only function is to create an instance of all of its test cases and then call on the test method of the test cases. To add a test case to a test suite, use the add(testCase) method when constructing the test suite. An example test suite for the conversion test cases is given below.

import jmunit.framework.cldc11.TestSuite;public class ConversionTestSuite extends TestSuite{  public ConversionTestSuite() { super("All Conversion Tests"); add(new DistanceConversionTest()); add(new TemperatureConversionTest()); }
Figure 3. Failure Test Case Console Output: Textual output in the case of failure indicates which test case failed, why it failed and provides a stack trace to see where it failed.

Executing JMUnit Tests
JMUnit's TestCase and TestSuite abstract classes are sub-classes of MIDlet. This allows you to run either your individual test cases or test suites in an emulator (or, unlikely but possible, a real device). When run on a simulator, each test case or test suite offers two commands: exit and test. Figure 1 depicts execution results of the tests suite described above. Figure 2 shows how failures are displayed.

You will also want to check the console when executing tests (see Figure 3). Failures, in particular, are better documented in the console output. Failure output includes stack trace information along with actual and expected values from the test. This might be one of the features regarding JMUnit that will disappoint you a little in comparison to J2MEUnit discussed next. Instead of console output, test case failures are actually displayed on the emulation device in J2MEUnit.

Working with J2MEUnit

Setting up J2MEUnit
The alternative to JMUnit is J2MEUnit. It, too, is downloaded via Sourceforge. Unlike JMUnit, there is only one version of J2MEUnit and thus only one .jar file. The current release is labeled 1.1.1.

J2MEUnit Test Cases
Test cases in J2MEUnit must inherit from j2meunit.framework.TestMethod. Like in JMUnit, your tests are implemented in test methods and conventionally named test+methodNameToBeTested. Unlike JMUnit, test methods are not required to throw any exception.

Importantly, J2MEUnit does not support as full or rich set of assert methods as does JMUnit. J2MEUnit only supports the following assertions:

assertTrue(expression)assertSame(expected,actual)assertEquals(expected,actual)assertNotEquals(expected,actual)assertNull(object)

Even these methods are not as overloaded as in JMUnit. As an example, Table 1 presents the types of expected versus actual types that can be compared in JMUnit's assertEquals method (both CLDC 1.0 and CLDC 1.1 versions) against J2MEUnit's assertEquals method. That's quite a few methods, especially in applications that use the new floating point types in CLDC 1.1.

 

JMUnit assertEquals

for CLDC 1.0

JMUnit assertEquals

for CLDC 1.1

J2MEUnit assertEquals

Expected value /result value

type support

Object

String

boolean

byte

char

int

long

short

Object

String

boolean

byte

char

double

float

int

long

short

Object

long

Except for the lack of assertion methods, J2MEUnit test case methods do not vary greatly from JMUnit test case methods. Example test methods for the DistanceConverstionTest are provided in Listing 1. Note the missing thrown exception; otherwise the methods look the same.

Like JUnit and JMUnit, J2MEUnit provides setup, teardown, and fail methods that can be overridden in test cases.

J2MEUnit TestSuite
The creation and execution of suites in J2MEUnit varies quite a bit from JMUnit. J2MEUnit suites are more reminiscent of regular JUnit suites (except for the lack of reflection).

In order to create a test suite in J2MEUnit, you typically create a suite() method in your test case class. This aligns closely with JUnit, although in J2MEUnit, the suite method can be an instance method. In regular JUnit, the suite method is a static method. The suite method returns an instance of j2meunit.framework.TestSuite. This object contains all the test methods for all the test cases that are desired.

Adding a test method for a test case to the suite can seem a little convoluted. The best way to add a test method to the suite is to create and use an instance of j2meunit.framework.TestMethod. TestMethod is actually an interface that stipulates a single run(TestCase) method be provided by implementing classes. TestMethods are generally implemented with an anonymous inner class. Here is how to add a TestMethod to the suite for the testfeetToMeters method:

public Test suite() { TestSuite suite=new TestSuite(); suite.addTest(new DistanceConverstionTest("testfeetToMeters",          new TestMethod(){			    public void run(TestCase tc){			     ((DistanceConverstionTest) tc).testfeetToMeters(); 			    }          } )); return suite;}

Of course, the other methods in DistanceConversionTest need to be added to the suite similarly, and the suite method also necessitates the creation of a test case constructor.

 public DistanceConverstionTest(String testName, TestMethod testMethod) {     super(testName, testMethod); }

Figure 4. A Successful Test Suite Execution.: Output using J2MEUnit is not as glitzy as JMUnit, but it still gets the pertinent information to the developer. The first screen shows the status of execution and the second screen displays the final results.
 
Figure 5. A Failure Test Case: More detailed information is provided in J2MEUnit on failures such as which test failed and what values were expected.

Executing J2MEUnit Tests
J2MEUnit test cases are not MIDlet sub classes as in JMUnit. Instead, J2MEUnit offers two implementations of a TestRunner class that allow you to execute your tests. j2meunit.textui.TestRunner parallels the idea in the regular JUnit's TestRunner. 2meunit.textui.TestRunner can only be executed from command line environments. Therefore, the preferred way to run J2MEUnit tests is to use the other TestRunner implementation. j2meunit.midletui.TestRunner is a MIDlet that you extend. As a MIDlet, j2meunit.midletui.TestRunner runs in an emulator (or real device).

Overrideing the startApp() method is the only thing you need to code in your TestRunner MIDlet class. In the startApp method call on TestRunner's start method with an array of Strings containing the names of your test case classes:

public class ConversionTestRunnerMIDlet extends TestRunner { protected void startApp() { start(new String[] {"com.white.tests.j2meunit.DistanceConversionTest","com.white.tests.j2meunit.TemperatureConversionTest"}); } }
Figure 6. Console Output: As with JMUnit, more detailed information is provided in the console window when executing J2MEUnit test cases. This is especially true in the case of failures.

Alternately, J2MEUnit allows for passing test cases to the MIDlet and executing the TestRunner directly by setting a J2MEUnitTestClasses property in the JAD file or JAR's manifest file. The J2MEUnitTestClasses property should contain a list of your test case classes.

The TestRunner MIDlet does not provide as flashy graphical results as JMUnit (see Figure 4), but on failures (see Figure 5), it does provide information in the emulator (unlike JMUnit).

As with JMUnit, more detailed information about the tests, especially failures, can be found in the resulting console window (see Figure 6).

Figure 7. Generate a JMUnit Test Case Class: NetBeans Mobility Pack 5.5 offers developers a simple menu option to create JMUnit CLDC 1.0 test case classes for any mobile application class.

NetBeans Integration
While both JMUnit and J2MEUnit can be used with just about any Java ME development environment or IDE like Sun's Wireless Took Kit, one IDE will soon release incorporated copies of these micro edition unit testing tools in its offering. NetBeans 5.5/NetBeans Mobility Pack 5.5 will ship with both of these tools. In fact, NetBeans will automatically generate JMUnit CLDC 1.0 tests for any J2ME project class. Simply right click on any class of Mobile project and ask to generate JUnit test classes from the Tools menu option (see Figure 7).

By default, NetBeans generates JMUnit CLDC 1.0 test cases. You can use a project's properties dialog window to add the JMUnit CLDC 1.1 or J2MEUnit library to the project and then manually create test classes and MIDlet test case runners of any type (see Figure 8).

Figure 8. Adding Libraries to a Project: NetBeans Mobility Pack 5.5 offers developers a simple menu option to create JMUnit CLDC 1.0 test case classes for any mobile application class.

To add either the JMUnit CLDC 1.1 or J2MEUnit libraries to a mobile project in NetBeans 5.5, right click on a project and select properties. On the subsequent window, select Build?>Libraries and Resources as shown in the figure and then hit the Add Library button to select the other JUnit libraries for use in your project.

According to members of the NetBeans project team, NetBeans 5.5 and NetBeans Mobility Pack 5.5 are expected to be released in late October. A Q-build release of both (with the Java ME unit testing frameworks) is available here.

The download files attached to this article not only contain all the classes demonstrated in this article, they also include NetBeans 5.5 projects that can be quickly and easily brought in to the new NetBeans IDE for exploration. Conversion 1.0 is a project that includes CLDC 1.0 version of the code examples along with JMUnit for CLDC 1.0 and J2MEUnit test cases. Conversion 1.1 is a project that includes CLDC 1.1 version of the code examples along with JMUnit for CLDC 1.1 test cases.

Future Java ME Unit Testing Looking Bright
No longer do you have the excuse that the quality of your Java Micro Edition application suffers because you don't have proper unit testing tools. JMUnit and J2MEUnit (and their soon to be merged incarnation) can provide valuable quality assurance assistance to micro edition developers.

As you can see, these two frameworks differ in a few areas. Many of the differences between the frameworks lie in the implementation details that are below the API most developers will use. JMUnit tends to provide a more rich set of assertions and may be a little easier to implement while J2MEUnit tends look and act a little more like regular JUnit at the suite level. Both offer some nice features that will hopefully be preserved in the merged product.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist