Wiki

Clone wiki

javarosa / UnitTesting

!JavaRosa Unit Testing

TracNav(JavaRosaTOC)

Unit testing in !JavaRosa is handled using the j2meunit libraries. There are a few different J2ME specific libraries out there, since Junit relies on reflection, which isn't available in J2me. The best option uses platform-specific tools, so we won't be using it. The other two (including j2meunit) are supposedly merging, so it's possible that this will change a bit in the future.

Unit Testing Infrastructure

Unit tests can be run on checked out branches at will, but are also run on the dev branch both nightly and on every SVN submission by our regression testing server. Any time these tests fail, an email message will be sent to javarosa-developers@googlegroups.com with the j2meunit output. This means that you shouldn't be committing new tests to the dev branch until they are going to pass. Tests in non-dev branches can fail at-will without problems.

Running Tests

Unit tests in !JavaRosa are launched from the main Ant build script, using the RunJ2MEUnitTests target. The project should build and launch the testing environment, writing the output to the console. You should see an output similar to

     [java] TestRunner.main()
     [java] ..
     [java] Time: 1ms
     [java] OK (2 tests)

Structure of Tests

The main entry point for the tests is the ant build target RunJ2MEUnitTests, which contains a list of test suites to run.

        <target name="RunJ2MEUnitTests" depends="disableObfuscator, BuildPolish" description="Runs j2mepolish Unit Tests on constructed jars">
		<property name="testresult.global" value="false"/>
		<RunTestSuite suite="org.javarosa.test.JavaRosaBasicTests"/>
		<RunTestSuite suite="org.javarosa.test.J2meUnitTest"/>
		<!-- add new test suites here -->
		<fail if="testresult.global=true">Unit Tests Failed!</fail>
	</target>

Each of these tests is run in the !RunTestSuite macro, which spawns a Java thread which runs the j2meunit with the name of a !TestCase class as an argument. This thread is spawned with this ant call, in the !RunTestSuite definition

		<java classname="j2meunit.textui.TestRunner" failonerror="true" fork="true" resultproperty="testresult.unittests">
			<classpath refid="classpath.test" />
			<arg value="@suite"/>
		</java>

J2ME Unit Testing

The org.javarosa.test.J2meUnitTest class extends the !TestCase class, which contains the tests to be run. Specifically, the important method in the J2meUnitTest class is suite(), which returns the test suite that will be run. Tests are created by adding them to a suite. One method of doing so is provided in the J2meUnitTest example:

	public Test suite() {
		TestSuite aSuite = new TestSuite();
		aSuite.addTest((new J2meUnitTest("testOne", new TestMethod() {
			public void run(TestCase tc) { ((J2meUnitTest)tc).testOne(); }
		})));
		aSuite.addTest((new J2meUnitTest("testTwo", new TestMethod() {
			public void run(TestCase tc) { ((J2meUnitTest)tc).testTwo(); }
		})));
				
		return aSuite;
	}

Each !TestCase file performs tests from the tests defined in the suite returned by the suite() method. These tests are defined as !TestMethods (Generally anonymously declared), which have a method run(!TestCase). Inside that method, the !TestCase can be cast to the proper type, and methods can be called from it (see example above).

The process is fairly complicated, but easy to complete if the existing test files and suites are used as examples.

Adding New Tests

New Tests can either be added to the existing test case files, given of course that they are added to the appropriate suite() constructor, or can be created as a new test suite, and added as a new j2meunit test thread in the RunJ2MEUnitTests class. For Example:

		<RunTestSuite suite="org.javarosa.test.JavaRosaBasicTests"/>
		<RunTestSuite suite="org.javarosa.test.J2meUnitTest"/>
		<RunTestSuite suite="org.javarosa.test.MyTestSuite"/>

Unit Testing To-do List

This section is a dumping ground to list out the general areas of JavaRosa that should get unit tests

  • IShell/IActivity interaction and contract
  • Context object(s)
  • Activity stack
  • Background daemons
  • JavaRosa Service Provider
  • Transport, Property, and Storage Managers
  • Utility code
  • Externalizable framework '''(in progress)'''
  • Data structures (Map, OrderedHashtable, SortedIntSet, ...)
  • Date/String functions
  • Form core (QuestionDef, FormDef, GroupDef, DataBinding, DataReference, Condition, etc.) '''(in progress)'''
  • Form model
  • IAnswerData '''(complete)'''
  • Instance object (DataModelTree, what have you...) '''(complete?)'''
  • Question Pre-/Post-processors
  • Localizer '''(complete)'''
  • Form Entry
  • Activity host
  • Form load
  • Reloading an already-saved form ('Form edit')
  • Controller
  • Views
  • Custom chatterbox widgets
  • Form Select
  • Form Send/Submit
  • Form Retrieve / 'Get New'
  • Saved Form List / Model List
  • Patient Record / DB
  • Patient Select / Entry
  • Referrals / Reminders
  • Login Activity
  • XForm parsing
  • Form definition
  • Instance
  • XForm instance serialization
  • XPath parsing '''(complete)'''
  • XPath evaluation '''(complete)'''

Updated