DRAFT
Testing for services
For examples of how to test services, please look at the repository fineract-cn-template.
...
Unit tests of the api module are located under <service>/api/src/test/. Most of these unit tests check the validation of domain objects. They should test happy cases and edge cases. To do this these tests consist of an initial version of the domain object, and a list of changes to the domain object, plus whether the change should produce a valid or invalid domain object. For an example see the SampleTest.
service
The service module contains the bulk of the executable code. Here unit tests are based on JUnit, and dependencies between classes are replaced using Mockito. We have chosen not to test all the code in a service this way. Instead we've leaned heavily on somewhat more holistic component tests. Good candidates for classes to unit test are:
...
If the component tests are programmed correctly, multiple tests can be run in one go. This saves a lot of clicking for the programmer, but it's also faster because the necessary infrastructure is spun up once at the beginning and then spun down at the end. Not all services have this ability, but those that do have a so-called TestSuite. All of the component tests for the service are entered in the TestSuite. A test which is entered in the TestSuite must derive from a SuiteTestEnvironment class which defines the environment for running tests for this service. Each service has its own requirements on its test environment so each has its own SuiteTestEnvironment.
...
To make this possible the libraries fineract-cn-test and fineract-cn-anubis contain some supporting code:
- TestEnvironment sets the public key for the simulated provisioner and keeps the corresponding private key around for future use. It's a so-called test resource with a before and after clause which are run automatically by the framework.
- TenantApplicationSecurityEnvironmentTestRule uses the TestEnvironment to create the necessary call to initialize, and to set a user token header in the REST calls to the service. In most cases a new user context is created for each test.
...
To support these needs, we've created an EventRecorder which can be used to note events and to wait for events. To use it, do four things:
- enable it using the @EnableEventRecording annotation on your test configuration,
- make sure that your event objects have equals and hashcode implemented,
- create a listener for the event in question, similar to the SampleEventListener. The listener should pass event notifications into the event listener.
- call eventRecorder.wait(<event id>, <location identifying object>) when you're expecting an event.
...
Because the EventRecorder collects all events that it "sees" in memory, it is not suitable for most production uses. It depends on the limited run times of component tests; in most other contexts its approach will be indistinguishable from a massive resource leak. If you want to wait for a specific event in production code, consider using EventExpectation instead.
Testing for libraries
...
We have a few classes in fineract-cn-service-starter which are intended to make this easier:
- InitializedMicroservice is a test rule which starts, initializes, and stops a service.
- ActiveMQForTest is a test rule which starts and stops ActiveMQ
- EurekaForTest is a test rule which starts and stops Eureka.
- IntegrationTestEnvironment which sets the necessary ports and environment variables for the services.
...