Module Unit Testing (old JUnit3 way)

This page describes how to do unit testing in OpenMRS 1.3 and earlier which used junit-3.8.
For the latest method for unit testing see Module Unit Testing

Getting Started

Unit testing in modules is very similar to unit testing the API.

To test a class that is not associated with the Context or your module service, unit testing is a two step process:

  1. Create your test class in /test/org/openmrs/module/yourmodule:
    package org.openmrs.module.yourmodule;
     
    public class MyModuleObjectTest extends TestCase {
    public void testShouldExamineFeatureXOfMyModuleObject() throws Exception {    MyModuleObject obj = new MyModuleObject();    String output = obj.someComplicatedCall("argument1");    assertNotNull(output);  }
    }
    
  2. Run your test class. In eclipse:
    1. Right click on the class name in the "Navigator" or "Package Explorer" view
    2. Select "Run As" ? JUnit Test

Testing the Your Module Service

To test a class that requires the Context object and method calls, simply extend BaseModuleContextSensitiveTest. The BaseModuleContextSensitiveTest class will run through the Spring setup, loads in any omods on the classpath, creates the Context and ServiceContext classes required by the OpenMRS API. This startup takes a few seconds, so when you can, create simple tests that only extend TestCase and do not call Context.* or your module's service.

  1. Compile the OpenMRS tests api using the package-api-tests ant target in OpenMRS's build.xml
  2. Copy the newly compiled jar file /dist/tests-openmrs-api-....jar to /lib-common folder of your module
  3. Set up the module classpath file (see below)
  4. Create your test class in your module /test/org/openmrs/module/yourmodule:...
    public class MyModuleServiceTest extends BaseModuleContextSensitiveTest {
    ...

Setting Up the Classpath for Module JUnit Testing

You will need to reference most openmrs libraries from your module code (file /.classpath). Your classpath will most likely look very similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="web/src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
&nbsp;
<classpathentry kind="lib" path="dist"/>
<classpathentry kind="lib" path="metadata"/>
&nbsp;
<classpathentry kind="lib" path="lib-common/openmrs-api-1.2.03.3940.jar" sourcepath="/openmrs-alpha"/>
<classpathentry kind="lib" path="lib-common/web-openmrs-api-1.2.03.3940.jar"/>
<classpathentry kind="lib" path="lib-common/tests-openmrs-api-1.2.03.3940.jar" sourcepath="/openmrs-alpha/test"/>
<classpathentry kind="lib" path="lib-common/commons-logging-1.0.4.jar"/>
<classpathentry kind="lib" path="lib-common/spring-2.5.1.jar" sourcepath="/openmrs-source/spring-2.5.1-src.zip"/>
<classpathentry kind="lib" path="lib-common/hibernate325.jar" sourcepath="/openmrs-source/hibernate-3.2.5ga-lite.zip"/>
<classpathentry kind="lib" path="lib-common/servlet-api.jar"/>
<classpathentry kind="lib" path="lib-common/velocity-1.6-dev.jar"/>
<classpathentry kind="lib" path="lib-common/commons-io-1.1.jar"/>
<classpathentry kind="lib" path="lib-common/spring-mock.jar" sourcepath="/openmrs-source/spring-2.0-src.zip"/>
<classpathentry kind="lib" path="lib-common/junit-3.8.1.jar"/>
&nbsp;
<classpathentry kind="lib" path="/openmrs/lib/mail/mail.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/jta/jta.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/dom4j/dom4j-1.6.1.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/commons-collections/commons-collections-3.1.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/mysql-connector-java/mysql-connector-java-3.1.10-bin.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/cglib/cglib-2.1_3.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/c3p0/c3p0-0.9.1.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/ehcache/ehcache-1.2.4.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/hl7api/hapi-0.5.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/antlr/antlr_2.7.6.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/asm/asm.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/jakarta-log4j/log4j-1.2.13.jar"/>
<classpathentry kind="lib" path="/openmrs/lib/xerces/xercesImpl.jar"/>
&nbsp;
<classpathentry kind="output" path="build"/>
</classpath>

Logging in JUnit Module Tests

  1. You must have log4j referenced explicitly in your .classpath file
  2. log4j.xml's parent folder must be in your classpath in order to be found by log4j (like in /metadata or /dist)
    • The log4j.xml can will look something like:
      <?xml version="1.0" encoding="UTF-8" ?>
      <\!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
      &nbsp;
      <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
      &nbsp;
      <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
      <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern"
      value="%p - %C{1}.%M(%L) \|%d{ISO8601}\| %m%n" />
      </layout>
      </appender>
      &nbsp;
      <logger name="org.openmrs.module.remoteformentry">
      <level value="DEBUG" />
      </logger>
      &nbsp;
      <root>
      <level value="ERROR" />
      <appender-ref ref="CONSOLE" />
      </root>
      &nbsp;
      </log4j:configuration>
      

Including Other Required Modules in JUnit Tests

  1. Package the required module into its omod file and drop it into the /lib-common folder

Extras

  • If you've added a log4j.xml file to your metadata directory and metadata is referenced in the .classpath file and you still don't see any log messages in the console during the execution of the test, make sure that the metadata directory comes before all JARs that might have a log4j.xml in them already (i.e. openmrs-api.jar)
  • If you create custom tables and map them using hibernate, an error in the <table_name>.hbm.xml can be masked and you will just get an error to the effect that your service cannot be found when you call Context.getService(<your_service>.class). If you compile the module and load it into the OpenMRS web interface, it will tell you the real error.
  • If you get an exception like org.openmrs.api.APIException: Service not found: class org.openmrs.module. ... then you may need to do one of two things. First, make sure that you have run the and "package module" task. If you've already done that, then you probably need to fix your build file for the module you're including.
    1. Open build.xml in the module you're compiling
    2. Find the "package-jar" target
    3. Remove the line like "<exclude name="*" />"
    4. Repackage your jar file and try using it again in the other module
  • To skip the authentication username/popup when testing, place these variables into your runtime properties file: junit.username=admin
    junit.password=test

FAQ

When I run my module's service tests, I get the following error:org.hibernate.MappingException: Unknown entity: org.openmrs.module.<module>.<Object>Hibernate will only look for your module's .hbm.xml mapping files in classpath:*.omod. You must have the reference to <classpathentry kind="lib" path="dist"/> in your module's /.classpath (see above).Note:Since /dist is now a referenced library, you might also need to make sure it is present at compilation time (Ant-clean deletes it). Rearrange your build.xml to create /dist before the compilation call.When running unit tests in Eclipse, I get the following error:org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '<JUnit Test Class>': Unsatisfied dependency expressed through bean property 'transactionManager': Set this property value or disable dependency checking for this bean.Make sure that you are using Spring version 2.5 or above. You can also add setDependencyCheck(false) to the constructor of your test class.