In this blog, I’m sharing an example project to show unit and integration test with Spring.
We have a web service for car. Here is the entity
And lets say we have a Dao for this entity as follows
Spring provides a custom test configuration for testing this Dao class. All you have to do is use
@DataJpaTest annotation in your test class.
@RunWith(SpringRunner.class) -> this part is required to use @Autowired or other spring related annotations to be processed.
TestEntityManager is used as a replacement of JPA’s EntityManager for executing SQL queries in test mode.
DataJpaTest will create an in-memory database for the runtime test environment.
By Default this mode is @Transactional which means after each test, the test db will be rolledback.
After completing the Dao test, we can go to next step which is unit test for
First of all, make sure to use Constructor injection, not field injection. This will be helpful when we write unit tests for this class.
This is the part of test class
We are using
@MockBean annotation for CarDao. Our intention here is, not running the whole Spring App but just run the CarService only. To accomplish that, we create the CarService instance and mock the all possible dependencies (for our case, it s just CarDao but it could be more than that).
With Mockito, we are mocking the behavior of carDao for specific methods and testing them through CarService methods. So we verify our service methods are working as we expected.
After completing the unit testing for the service class, we can do the integration testing of RestController.
This is our rest controller
And this is the integration test
The main difference here is the
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) annotation. This is starting the app in random port.
We are using TestRestTemplate as client to execute REST requests.
Since this test code is also running in spring context, we can inject CarDao here for inserting dummy data to our test database and pull it through rest calls.
I’d highly recommend to use a test profile with test environment database configuration in it to make sure you are in control with your application status during testing.
All you have to do is to add
@ActiveProfiles("your-test-profile-name")to your test class.
In integration test, the test methods are not in transactional mode which means they will not be rolled back after each test execution. Therefore you should be careful about not changing the applications state between tests. Since Junit is not running the tests in order (which can be configured to run in order but I wouldn’t suggest it), if any test would be leaving unexpected data in db, it may break other tests. So make sure you return to your original state after the test is completed. You can use @Transactional annotation. Or you can add a method to clear the database after each test run and you make sure it with