How to write unit tests in inspectIT
This page shows how you best write unit tests in inspectIT
Tooling
These are the tools we are using for testing:
- TestNG: As testing framework. We decided to move from junit to testNG some years ago when junit seemed to be stuck
- Mockito: To allow easy mock-based testing.
- Hamcrest: To allow to read the asserts in a human-understandable way.
Testing a spring-based service or standard Java class
Actually this is the situation that you very often will write unit tests. You created or extended a service and want to ensure that it is working. So this is what you want to do:
- Create a class that mirrors the package structure of your testee, call the class like the Testee and put Test at the end. Normal source code belongs in the src folder, test code go to the test folder (the test for info.inspectit.service.VersionService is thus info.inspectit.service.VersionServiceTest)
- Extend from info.novatec.inspectit.testbase.TestBase or another subclass of TestBase (like AbstractLogSupport).
- Each method should test exactly one situation, prefer to write more test methods than to have everything within one test method
- The structure of the unit test class should include one inner class per method to test against and in this inner class are the testng test method. This helps in realizing very quickly which method is already tested and which test cases are covered.
Here is an example:
This example is based on the class ReflectionCache with the test ReflectionCacheTest.
The interesting structure of the base java class is:
public class ReflectionCache { ... some fields ... public <T> T invokeMethod(final Class<?> clazz, String methodName, Object instance, Object[] values, T errorValue) { ... method content ... } }
Thus we create a test class which will look like the following:
public class ReflectionCacheTest extends TestBase { /** Class under test. */ @InjectMocks ReflectionCache cache; /** Tests for the {@link ReflectionCache#invokeMethod(Class, String, Class[], Object, Object[], Object)} method. */ public static class InvokeMethod extends ReflectionCacheTest { @Test public void normalUsage() { String testString = "I am a test"; String result = (String) cache.invokeMethod(String.class, "toString", testString, null, null); assertThat(result, is(testString)); } @Test public void multipleInvocationOnSameObject() { ... test method content ... } @Test public void methodWithParameter() { ... test method content ... } ... more test methods ... } }
Two important remarks about this test setup:
- The class under test should be marked with @InjectMocks even if no @Mock fields are going to be injected. This is because before every test method execution, this field will be reset.
- The inner class has to extend the outer test class. This is needed to access the in this example the cache field.