In this page is described the solution to the
JMUnit TestSuite execution problem. This is a new approach that follow the general idea of
JMUnit Revised 1.0 without breaking any of the JMUnit 1.2.1 CLDC 1.1 features.
Solution
Exploring JMUnit 1.2.1
src_cldc11 folder it is easily found the inheritance chain that ends in
MIDlet:
Top
Description
To make TestSuites work this inheritance chain has to be broken:
The process followed to break the inheritance chain is:
- Modification of Assertion and elimination of MIDlet class references.
- Modification of Test to store a MIDlet as a class member. To initialize it a new static method is present, initialize(MIDlet). Elimination of overriden MIDlet's methods and
inclusion of methods to manage MIDlet's states.
- Modification of TestSuite to use the MIDlet stored in Test to get the the custom property JMUnitTestClasses from the Application Descriptor in order to parse the defined TestCases.
It is also necessary to modify
GuiListener as the
MIDlet is displayed in the mobile screen in this class. The following line of code in GuiListener's constructor:
Display.getDisplay(testMidlet).setCurrent(this.screen);
, changes to use the
MIDlet reference from
Test:
Display.getDisplay(Test.midletRef).setCurrent(this.screen);
This process is retained in a patch that could be downloaded from the
Downloads page. The patch doesn't update JMUnit tests for CLDC1.1, so they shouldn't be run.
Top
Patching JMUnit 1.2.1 CLDC 1.1 sources
- Download JMUnit 1.2.1 sources and extract them in a directory of your choice.
macbook:jmunit-revised usuario$ ./wget http://downloads.sourceforge.net/project/jmunit/JMUnit/JMUnit%201.2/jmunit-1.2.1.zip
--2009-08-04 04:23:42-- http://downloads.sourceforge.net/project/jmunit/JMUnit/JMUnit%201.2/jmunit-1.2.1.zip
Resolving downloads.sourceforge.net... 216.34.181.59
...
2009-08-04 04:23:46 (782 KB/s) - `jmunit-1.2.1.zip' saved [2250596/2250596]
macbook:jmunit-revised usuario$ mkdir jmunit-1.2.1
macbook:jmunit-revised usuario$ unzip jmunit-1.2.1.zip -d jmunit-1.2.1
Archive: jmunit-1.2.1.zip
creating: jmunit-1.2.1/dist/
...
- Download the patch jmunit-revised-2.0-patch.tar.gz and extract it in a directory of your choice.
macbook:jmunit-revised usuario$ tar zxf jmunit-revised-2.0-patch.tar.gz
- Move the file patch.jmunit to JMUnit root directory and execute the patch command.
macbook:jmunit-1.2.1 usuario$ patch -p0 < patch.jmunit
patching file src_cldc11/jmunit/framework/cldc11/Assertion.java
patching file src_cldc11/jmunit/framework/cldc11/GuiListener.java
patching file src_cldc11/jmunit/framework/cldc11/Test.java
patching file src_cldc11/jmunit/framework/cldc11/TestCase.java
patching file src_cldc11/jmunit/framework/cldc11/TestRunner.java
patching file src_cldc11/jmunit/framework/cldc11/TestSuite.java
...
- Compile cldc1.1 sources, src_cldc11 folder, and use the modified library instead of the
original.
Top
Modified sources usage
As
Test is no longer a
MIDlet, therefore tests won't start automatically and a
MIDlet must be created so that
Test could be initialized.
The usage of
TestCase,
TestSuite and
TestRunner does not vary from the original JMUnit sources besides the fact that they must be started in the
MIDlet startApp method:
- To start a TestRunner the method doStart is used.
- To start a TestSuite or TestCase the method start is used.
A
MIDlet example for each of these three classes is shown below. For a neat and tidy code it is recommended to follow the
Advance modified sources usage.
Example 1: MIDlet for executing a TestSuite
import javax.microedition.midlet.*;
import jmunit.framework.cldc11.*;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class JMUnitRevisedMIDlet extends MIDlet {
public void startApp() {
//Initialize Test
Test.initialize(this);
Test test = new MyTestSuite();
//start
test.start();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Top
Example 2: MIDlet for executing a TestRunner
import javax.microedition.midlet.*;
import jmunit.framework.cldc11.*;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class JMUnitRevisedMIDlet extends MIDlet {
public void startApp() {
//Initialize Test
Test.initialize(this);
Test test = new MyTestRunner();
//start
test.doStart();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Top
Example 3: MIDlet for executing a TestCase
import javax.microedition.midlet.*;
import jmunit.framework.cldc11.*;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class JMUnitRevisedMIDlet extends MIDlet {
public void startApp() {
//Initialize Test
Test.initialize(this);
Test test = new MyTestCase();
//start
test.start();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Top
Advance modified sources usage
In the previous section a new runner (a
MIDlet) was created in a different file from the tests. This could be avoided following two approaches related to the use of static nested classes as suggested by
C. A. Meijer.
- Including the runner as a static nested class of the test.
- Or including the test as a static nested class of the runner.
Runner as static nested class
Example 1: TestCase with static nested runner class
package com.my.tests;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import jmunit.framework.cldc11.AssertionFailedException;
import jmunit.framework.cldc11.Test;
import jmunit.framework.cldc11.TestCase;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class MyTest extends TestCase {
public MyTest() {
super(2,"MyTest");
}
public void test1() throws AssertionFailedException {
}
public void test2() throws AssertionFailedException {
}
public void test(int testNumber) throws Throwable {
switch (testNumber) {
case 0:
test1();
break;
case 1:
test2();
break;
default:
break;
}
}
public static class MyTestRunner extends MIDlet {
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
//Initialize Test
Test.initialize(this);
//Instantiate TestCase
Test test = new MyTest();
//start
test.start();
}
}
}
The
MIDlet class definition in the Application Descriptor would be as follows:
MIDlet-1: MyTestRunner,,com.my.tests.MyTest$MyTestRunner
And the custom property that lets the default constructor of
TestSuite read the tests from the Application Descriptor would be:
JMUnitTestClasses: com.my.tests.MyTest
Example 2: TestSuite with static nested runner class
package com.my.tests;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import jmunit.framework.cldc11.Test;
import jmunit.framework.cldc11.TestSuite;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class MyTestSuite extends TestSuite {
public MyTestSuite() {
super();
}
public static class MyTestSuiteRunner extends MIDlet {
public void startApp() throws MIDletStateChangeException {
//Initialize Test
Test.initialize(this);
//Instantiate TestSuite
Test test = new MyTestSuite();
//start
test.start();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) throws MIDletStateChangeException {
}
}
}
The
MIDlet class definition in the Application Descriptor would be as follows:
MIDlet-1: MyTestSuiteRunner,,com.my.tests.MyTestSuite$MyTestSuiteRunner
Example 3: TestRunner with static nested runner class
package com.my.tests;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import jmunit.framework.cldc11.Test;
import jmunit.framework.cldc11.TestSuite;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class MyTestRunner extends TestRunner {
//Tests to run: TestCase or TestSuite
private Test test = new MyTest();
//Delay to let the user see the display
private static final int DELAY = 1000;
public MyTestRunner() {
super(DELAY);
}
protected Test getNestedTest() {
return test;
}
public static class MyTestRunnerMIDlet extends MIDlet {
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
//Initialize Test
Test.initialize(this);
//Instantiate TestRunner
Test test = new MyTestRunner();
//start
test.doStart();
}
}
}
The
MIDlet class definition in the Application Descriptor would be as follows:
MIDlet-1: MyTestRunnerMIDlet,,com.my.tests.MyTestRunner$MyTestRunnerMIDlet
Test as static nested class
Example 1: TestCase as static nested class
package com.my.tests;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import jmunit.framework.cldc11.AssertionFailedException;
import jmunit.framework.cldc11.Test;
import jmunit.framework.cldc11.TestCase;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class MyTest extends MIDlet {
private static Test myTestImpl;
public static Test getTestImpl() {
if (null == myTestImpl) {
myTestImpl = new MyTest.MyTestImpl();
}
return myTestImpl;
}
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
//Initialize Test
Test.initialize(this);
//Instantiate TestSuite
Test test = MyTest.getTestImpl();
//start
test.start();
}
public static class MyTestImpl extends TestCase {
public MyTestImpl() {
super(2,"MyTestImpl");
}
public void test1() throws AssertionFailedException {
}
public void test2() throws AssertionFailedException {
}
public void test(int testNumber) throws Throwable {
switch (testNumber) {
case 0:
test1();
break;
case 1:
test2();
break;
default:
break;
}
}
}
}
The
MIDlet class definition in the Application Descriptor would be as follows:
MIDlet-1: MyTest,,com.my.tests.MyTest
And the custom property that lets the default constructor of
TestSuite read the tests from the Application Descriptor would be:
JMUnitTestClasses: com.my.tests.MyTest$MyTestImpl
Example 2: TestSuite as static nested class
package com.my.tests;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import jmunit.framework.cldc11.Test;
import jmunit.framework.cldc11.TestSuite;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class MyTestSuite extends MIDlet {
private static Test myTestSuiteImpl;
public static Test getTestSuiteImpl() {
if (null == myTestSuiteImpl) {
myTestSuiteImpl = new MyTestSuite.MyTestSuiteImpl();
}
return myTestSuiteImpl;
}
public void startApp() {
//Initialize Test
Test.initialize(this);
//Instantiate TestSuite
Test test = MyTestSuite.getTestSuiteImpl();
//start
test.start();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
private static class MyTestSuiteImpl extends TestSuite {
public MyTestSuiteImpl() {
//Add TestCases
add(MyTest.getTestImpl());
}
}
}
The
MIDlet class definition in the Application Descriptor would be as follows:
MIDlet-1: MyTestSuite,,com.my.tests.MyTestSuite
Example 3: TestRunner as static nested class
package com.my.tests;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import jmunit.framework.cldc11.Test;
import jmunit.framework.cldc11.TestRunner;
/**
* @author francisco.benitez.leon@gmail.com
*/
public class MyTestRunner extends MIDlet {
public void startApp() {
//Initialize Test
Test.initialize(this);
//Instantiate TestRunner
Test test = new MyTestRunnerImpl();
//start
test.doStart();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
private class MyTestRunnerImpl extends TestRunner {
//Tests to run: TestCase or TestSuite
private Test test = MyTest.getTestImpl();
//Delay to let the user see the display
private static final int DELAY = 1000;
public MyTestRunnerImpl() {
super(DELAY);
}
protected Test getNestedTest() {
return test;
}
}
}
The
MIDlet class definition in the Application Descriptor would be as follows:
MIDlet-1: MyTestRunner,,com.my.tests.MyTestRunner
Downloads
Top