Unit Testing


Contents

We are currently using JUnit for unit testing. See Unit Test Conventions.

Getting Started

To test a class that is not associated with the Context unit testing is a two step process:

  1. Create your test class in /test/api/org/openmrs:
    package org.openmrs;
     
     public class MyObjectTest extends TestCase {
       public void testFeatureAOfMyObject() throws Exception {
         MyObject obj = new MyObject();
         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
  3. No number 3! I said only a "2 step process"! Go! Test your world!

A good example of a basic junit test would be the RoleTest

Testing the OpenMRS API (and Other Context Sensitive Classes)

To test a class that requires the Context object and method calls, simply extend BaseContextSensitiveTest. The BaseContextSensitiveTest class will run through the Spring setup to create 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.*.

  1. Create your test class in /test/api/org/openmrs/api:
    ...
     public class MyServiceTest extends BaseContextSensitiveTest {
     ...
  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

A good example of a Context sensitive junit test would be the UserServiceTest

By default, the Context is set up to run against an in-memory database called hsql. This database is automatically built from the hibernate mapping files that Spring knows about. To use your mysql database defined by your runtime properties, override the BaseContextSensitiveTest.useInMemoryDatabase() method and have it return false.

If you are running against the in-memory database, you need to do something like this:

...
 initializeInMemoryDatabase();
 authenticate();
 executeDataSet("org/openmrs/synchronization/engine/include/SyncCreateTest.xml");
 ...

An example of an xml dataset definition is initialInMemoryTestDataSet.xml. (This code is automatically run by the initializeInMemoryDatabase() call.)

If you don't want to hand-write the XML, you may follow the strategy detailed in CreateInitialDataSet.java.

Batch JUnit Testing

  1. Run the ant target junit-report found in the OpenMRS build.xml file
  2. The generated reports can be viewed with /build/junit-report/index.html

JUnit Environment Variables

JUnit Environment variables can override system environment variables. For example, if you want a different OPENMRS_RUNTIME_PROPERTIES_FILE for JUnit.

  1. Right Click on a JUnit test. For example, CreateInitialDataSet.java.
  2. Select Run As --> Open Run Dialog
  3. Select the Environment tab and add a New environment variable.
Enlarge

Resources

FAQ

How do I create a method in my junit test class that will not be run as a test method?
The only methods run by JUnit are named test____. Just don't start your method name with 'test'.
How can I authenticate to the Context without putting my username and password in the code?
Use the authenticate() method found in BaseContextSensitiveTest
That authenticate method is awesome...but I want to authenticate without user intervention. How can I do that easily?
Define two properties in your runtime properties file: junit.username and junit.password.
How can I have my Context sensitive tests actually commit to the database instead of rolling back at the end of the tests?
Call the setComplete() method in your test method (Note: This only makes sense if you've chosen to not use the in-memory hsql database)
Why am I getting the error org.openmrs.api.APIException: Service not found: interface org.openmrs.api ..... in my unit test?
You're trying to use a basic unit test to do Context/API testing. Extend BaseContextSensitiveTest instead of just TestCase
Why am I getting the error org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here in my test?
You're probably calling either BaseContextSensitiveTest.getConnection() or initializeInMemoryDatabase() outside of the transaction. It is best to call this from either onSetUp''<u>In</u>''Transaction or from your test methods
Is there a tool for creating the xmls used in the unit tests or are they made by hand?
You can write it by hand if you want, but the easiest way is to generate the xml off of your current openmrs database. Use the org.openmrs.test.CreateInitialDataSet file to generate it.