-
Notifications
You must be signed in to change notification settings - Fork 12
CT Unit Tests
NOTE: Either perform a JUnit + Mockito - based unit tests with no Spring auto-wiring or perform Spring integration tests with use of autowiring. Don't mix these two.
When we mix autowiring with test doubles from Mockito, autowiring wins and the code throws an exception.
As mentioned above, for writing unit tests for a class we resort to using JUnit and Mockito to carry out the required operations. So it's necessary to follow the below mentioned steps:
Make use of @Data
annotation as explained here. This will be useful when we create the test-class. Also Check if any class dependency hasn't been auto-wired. Autowiring helps us perform Dependecy Injection which is required to write an extensive Unit-Test. We use Field Autowiring, instead of Constructor or Setter Autowiring as Mockito has a restriction of creating Mocks for only either of the three and writing code for the latter two is very troublesome.
To understand how to autowire dependencies/ understand what it is refer this
After you have Autowired your concerned class' dependencies, the concerned class receives them as Beans through the Spring IoC container or we explicitly provide them through a Config Class. To understand what beans are, refer this. As an example consider Class SaveRepository. So, now any beans that have to be provided to it explicitly are provided through its config class which will rightly be named as SaveRepositoryConfig. (Naming Conventioned followed - Add "Config" after the concerned class' Class Name").
As SaveRepository is present in /src/main/java/in/ac/bits/protocolanalyzer/persistence/repository
package, the corresponding config class will also have a similiar path url. In the case of SaveRepositoryConfig it will be present inside /src/main/java/config/in/ac/bits/protocolanalyzer/persistence/repository
package.
The final step is to use the @ComponentScan
annotation in our concerned class' (SaveRepository) class-definition. Refer this so as to understand why it is done.
As we provide our Concerned Class (SaveRepository) the beans it needs through its Config Class (SaveRepositoryConfig) at runtime, we need to simulate the same behavior for our Integeration Tests as well. What this means is that the Beans created in the SaveRepositoryConfig are needed to be added in the config class of our Integration Test(named: ExperimentTest) which is ExperimentTestConfig. So simply add all the bean creation code from ConcernedClassConfig to IntegrationTestConfig (SaveRepositoryConfig to ExperimentTestConfig)
NOTE: As of now we have only 1 Integration Test (ExperimentTest) , we do this only for its Config Class. If there are more Integration Tests in place, then we will have to repeat this step of copying bean declarions for the concerned class to all of the Integration Test Configs in existence.
Continuing with our example, the Test Class for SaveRepository is SaveRepositoryTest. (Naming Convention Followed - Add "Test" after the Class under Test's Class Name). As SaveRepository had /src/main/java/in/ac/bits/protocolanalyzer/persistence/repository
as its classpath, the corresponding Unit-Testing Class (in this example SaveRepositoryTest will be rightly located in the /src/test/java/unit/in/ac/bits/protocolanalyzer/persistence/repository
package.
To start-off with writing the tests, we to annotate our Test Class with @RunWith(MockitoJUnitRunner.class)
. This tells Spring that the Runner Class for the particular Test Class is Mockito. Next step is to create mocks/spies of the fields that are being Autowired in the Class under Testing. We can use Mockito's Annotations here. We use @Mock
or @Spy
just before declaring those Class-Dependency fields (Fields that are autowired in the Class under Testing) in the Test Class.
After this we can begin writing the Tests. Like in any other Unit Test, we first create an object of the Class under Testing but this time we also annotate it with @InjectMocks
. This tells Spring where those mocks created are to be injected into. So the next logical step is to call for the injection of the Mocks (perform dependency injection) into the Class under Testing's newly created object. This is done by the MockitoAnnotations.initMocks(this)
command. This command is usually written inside one of the @Before
methods. By doing this our Test Object is ready to be tested before every Test Function is called upon by the Mockito Runner Class. We write tests the usual way, by adding the @Test
annotation over the test function. Inside these test functions we use numerous assert statements. To assert things we use the extensive library of Hamcrest Asserts instead of JUnit Asserts.
- Development Workflow
- Coding Standards
- Coding Style
- Code Profile
- Coding Tutorials
- Branch History
- Refactoring Suggestions