Projects‎ > ‎JMUnit Revised‎ > ‎

JMUnit Revised 2.0

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:
  1. Modification of Assertion and elimination of MIDlet class references.
  2. 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.
  3. 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

  1. 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/
    ...
  2. 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
  3. 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
    ...
  4. 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.
  1. Including the runner as a static nested class of the test.
  2. 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