Tests in OpenMRS are being run with every commit by ci.openmrs.org and travis-ci.org/openmrs.
We aim to start organizing tests in OpenMRS codebase into five categories:
- Unit Tests
- Component Tests
- Integration Tests
- Performance Tests
- Manual Tests
If you look at our codebase, you will see many tests do not follow guidelines outlined below. In fact the guidelines are yet to be further adjusted and discussed.
The priority is not to clean up old tests rather write new tests following the best practices.
Unit Tests
JUnit is the test framework we use in OpenMRS core and modules. In addition we use Mockito to create mocks (simulated objects). Here are a few guidelines you should stick to when writing unit tests:
- Each class should have a corresponding class with unit tests e.g. Concept should have a corresponding ConceptTest class.
- If you have a class implementing an interface, then create a test class for the actual implementation.
- Classes with unit tests may extend BaseContextMockTest, if they need to mock legacy code calling services with Context.get...Service().
- Classes with unit tests must not extend BaseContextSensitiveTest and its subclasses BaseWebContextSensitiveTest, BaseModuleContextSensitiveTest, BaseModuleWebContextSensitiveTest.
- The test method should start from the tested method name (unit of work) followed by "_should" and the expected behavior e.g. toString_shouldIncludeNameAndDescriptionFields_ifNotBlank. "_if" should be included if the expected behavior depends on some state/condition.
- It is considered a good practice to follow //given //when //then pattern in tests:
(EXAMPLE HERE) Always assert with assertThat using static import for org.junit.Assert.* (explained here). The use of assertFalse, assertTrue, assertEquals is deprecated and not allowed in new tests.
- Prefer implementing FeatureMatcher if you cannot find any suitable matcher in Matchers.*.
- Prefer using @Mock annotated test class fields for creating mocks and @InjectMocks for injecting them into tested objects. See BaseContextMockTest.
Component Tests
Integration Tests
Integration tests are tests run against an instance of OpenMRS. Currently our integration tests focus on testing the Reference Application user interface.
The key points are:
- We are using docker to startup an OpenMRS server on Travis-CI before running tests (fresh instance including database for the whole test suite)
- Tests are executed by Travis-CI.
- Saucelabs is used as a client with a browser driven by tests. Saucelabs connects to the server instance running on Travis-CI through a tunnel (no access to the test server from the outside world).
- We test on Firefox 42 and Chrome 48.
- We run tests in parallel (currently 5 at a time).
- Tests should be added under https://github.com/openmrs/openmrs-distro-referenceapplication/tree/master/ui-tests/src/test/java/org/openmrs/reference.
- Each test class should be named starting with a verb, which best describes an action that is being tested, e.g. SearchActiveVisitsTest. By convention all test class names must end with Test.
- In general each class should contain one test method (annotated with @Test and @Category(BuildTests.class) and the test method should start with a verb and can provide a more detailed description of what is being tested than the class, e.g. searchActiveVisitsByPatientNameOrIdOrLastSeenTest. In rare cases we let test classes to have more than one test method. If a test class has more than one test method, those methods will never run in parallel.
- The test method should not visit more than 10 pages and should have 3-15 steps.
- You must not access Driver in a test. It is only allowed to perform actions calling methods in classes extending Page.
- It is not allowed to call Driver's methods in a page. You should be calling methods provided by the Page superclass.
- Each test class should start from homePage and extend ReferenceApplicationTestBase.
- It is not allowed to instantiate classes extending Page in test classes. They must be returned from Page's actions e.g. ActiveVisitsPage activeVisitsPage = homePage.goToActiveVisitsSearch();
- Do not store pages in class fields as it suggests they can be used for other tests.
- Each page should have a corresponding class, which extends Page and it should be added under https://github.com/openmrs/openmrs-distro-referenceapplication/tree/master/ui-tests/src/main/java/org/openmrs/reference/page
- The page class should be named after page's title and end with Page.
- Elements of the page must be found by id or class attributes. It is not allowed to find them by xpath expressions unless absolutely necessary. Locators must be defined as private (not public) static final fields of the class. See CSS Selectors.
For reference please use https://github.com/openmrs/openmrs-distro-referenceapplication/blob/master/ui-tests/src/test/java/org/openmrs/reference/SearchActiveVisitsTest.java and https://github.com/openmrs/openmrs-distro-referenceapplication/blob/master/ui-tests/src/main/java/org/openmrs/reference/page/ActiveVisitsPage.java
In case of questions, please write on talk.openmrs.org.
Performance Tests
To be addressed...
Manual Tests