Create a tool for helping the developers to write simple and maintainable unit tests with minimal effort on the tedious part and let them focus on the important part of the tests.
This plugin promotes the “Test First” approach. Create a well structured test method skeleton from the method signature with
Additional features:
Spring support:
This plugin has reasonable default settings for creating test method skeletons, but you’ll need to extend and fine tune those settings based on the ever changing requirements of your specific project. The plugin has a configurable set of default values for the input parameters, imports, naming conventions and so on. Feel free adjust these settings according to your needs. Please remember, that testing is a continuous effort that is part of the development task. The test implementation evolves together with the production code, just like the tools that we use.
You can find the samples below on GitHub. Feel free to clone this repository and play around with the test generation functionality of the plug-in.
This is the simplest case as the test class does not need any specific annotation, and no need to initialize the tested class either.
Base class | Test class |
---|---|
Note, that the gherkin style comments are separating the test method body to distinct blocks that clearly shows what are prerequisites, what is tested and what do we check.
For simple input parameters (i.e. primitive types) the plug-in is setting some predefined default values instead of leaving them uninitialzed. Same goes for the return value, that an assertEquals will be generated with a predefined default value.
For example
Base class | Test class |
---|---|
There will be a preference page for the plug-in to set up the default values you prefer, although it’s just a formality as you’ll need to customize the values anyway according to the logic of the method you’re testing. The main goal of this functionality to reduce the manual effort on writing the initialization steps and the assert clause.
When the method has no return value (i.e. void), then you’ll need to test for some “side effect”, like these
assertThat(param.getChangedField()).isEqualTo("new value");
verify(otherService).otherMethod("some value");
assertThrows(SomeException.class, () -> underTest.someMethod("some value");
assertDoesNotThrow(() -> underTest.someMethod("some value");
Since it’s vary what the side effects can be, the plug-in only generates a TODO
comment only.
For example
Base class | Test class |
---|---|
One of the most tedious part of writing a unit test is the preparation of input parameters when mocking is not sufficient. Mocking an input parameter is only useful when you have an interface or a class that is not a Java Bean (i.e. a service or function).
On the other hand, when you need to deal with data then you need to prepare that item with all it’s fields that are relevant for that method. This can require a big effort and lot of extra work.
See the example in the case above, where the method had the DemoObject
input parameter. The generated test initializing the parameter with the
TestValueFactory.
Using TestValueFactory is a nice workaround for this problem. It prefills all fields of given data object (e.g. Java Bean) with consistent and predictable values. So you can rely on that the input data is always the same and you only need to take care of the fields that are special related to that function. For example
But in most of the cases it’s enough to have the default values generated by the factory.
If the input parameter is not a primitive value, then the generator assumes that the TestValueFactory should be used instead and generates to code accordingly (see below).
When the tested method is producing a complex data structure in the response, then it can be tedious to test all of details of that object. Either you’re expecting that only a handful of properties were changing as a “side-effect” of the method execution, or all of the fields are important because it the method is creating a new object based upon the input parameters (e.g. a converter from an entity to a DTO).
Base class | Test class |
---|---|
In my opinion, this makes the test maintenance way easier and this way the test can detect (and protect from) accidental changes resulting from changes in the data model. It may sound controversial, but actually this can help a lot.
For example, the data model is changing in the application and the developer would forgot that this change affects a certain service or converter that is consuming or producing the changed element. The test would show automatically that the output is different from the previously known and expected form. This at least raises the important question: does this class need to be changed also in order to handle the new field, or the field removed is still needed, etc. The answer might be “yes it’s okay”, then update the JSON file in the test-resources folder and done. But in several cases the answer is “oops, I forgot about that this needs to be handled here as well”.
Also note, that the usual testing that is focusing only on the known fields would not detect this problem.
The same solution can be used to check if a dependent service was triggered with the right object. For example, if the method supposed to save an entity to the database with specific field values, then use the following pattern.
ArgumentCaptor<SomeEntity> entityCaptor = ArgumentCaptor.forClass(SomeEntity.class);
verify(someRepo).save(entityCaptor.capture());
assertThat(TestUtils.objectToJson(entityCaptor.getValue()))
.isEqualTo(TestUtils.readTestFile("dbtestfiles/SomeEntity_saved.json"));
Spring tests are slightly different than the usual basic or mocked test classes. These tests are instantiating a Spring context when they are running, that comes with it’s pros and cons. Advantages:
Disadvantages:
Formal differences:
Good practices:
One important part of testing a class that has some dependencies (i.e. injected fields), that these fields need to be mocked properly.
You can use either Mockito or Spring extensions to execute these tests. There are slight differences in how the class and the fields are annotated, as described above.
Base class | Test class with MockitoExtension | Test class with SpringExtension |
---|---|---|
Note, that
@ExtendWith(SpringExtension.class)
is superfluous, that’s why it’s not generated.
A special case of testing Spring components when we need to write tests for REST controllers or other public endpoints of the Spring application.
The plug-in generates an enhanced test method for these endpoints that were implemented in methods annotated with some RequestMapping
annotation (e.g. GetMapping
).
The test class is going to initialize a MockMVC
component and the test methods are calling the HTTP endpoint instead of direct method calls.
Base class | Test class |
---|---|
Note, it’s better keeping these tests in a separate test class considering the “integrated flavour” and that these a running slightly slower than the other tests. The checking of the results can be also trickier than with the mocked tests. Use the integrated tests only for checking the functionality that depends on the framework (i.e. is the endpoint available instead of resulting a HTTP 404 error, are the default values for the parameters correctly handled, the values correctly parsed from a JSon payload, etc).