Hello stackoverflow community.
I had an argument at work regarding if repository tests for spring-data JPA (or the Micronaut version) are necessary at all.
This would be my setup of the application:
@Controller
➡ @Service
/@Sigleton
➡ Repository<Entity>
in my service tests I'd use the @ExtendWith(SpringExtension::class)
extension (Junit5)
when creating the test setup, I'd @MockBean
away other systems I need to call (like REST-APIs) but @Autowire
my Repository
's.
When setting up my test data I'd simply save my required entities into an H2 in-memory database by using the injected repositories.
This will test my database logic and business logic as well. In case of 100% test coverage I've tested all the database calls which can happen in production.
However what I usually see in projects is that the Repository
is mocked away.
To test the custom repository calls there are separate Tests to make sure the repository functions work as expected.
What are your comments on this. Do you prefer the approach without repository mocks or with and why?
I have no experience with Micronaut, but I believe my answer will apply to both of the frameworks:
There are different types of integration tests supported by spring for example. Basically the fact that you're running a spring context in the test, already means that its more than a unit test. In general the Spring test package is for integration tests.
Now in Spring there are annotations like @DataJpaTest
, @WebMvcTest
. They create a "slice" of application context loading only necessary beans, and mocking / omitting others. For example, in @WebMvcTest
the JPA repositories are anot loaded at all.
You can also create your own slices.
Now If you want to check your rest layer (Controller is defined correctly, request is validated in a proper way, upon the request you're getting a response in a proper format and so forth) you can use @WebMvcTest
.
If you want to test that the sql queries are correct - that you can use @DataJpaTest
(assuming you work with JPA / Spring Data of course).
Now, If you want to test service logic, sometimes you don't even need an integration test (loading spring context) since you can run a unit test for services and mock out the repository calls or calls to external services if you have those.
Regarding the H2 approach. While people use it for testing their DB layer (SQL queries), sometimes it doesn't work exactly like your database in production. This means that sometimes you can't really run the same SQL query in tests. For these cases I recommend TestContainers project: run the Docker image of your db on startup of the test and stop the image after the test ends.
Update
Based on OP's comment:
lot of the 'mysql query' is already been taken care of by the framework, so why should I explicitly test the repository
This is subjective, but let me put it this way: Tests are a tool to gain a confidence a code for developer first of all. If the developer wants to be sure that the query behaves as expected then the test is a tool that can help. Specifically regarding Queries: Maybe the query is just wrong, maybe its a native query that should be checked anyway. Maybe there are many queries that run one after another. Its only up to you to decide.
Is it worth it to write Unit tests for services?
Well, this depends on what do the services actually do. If they run a complicated algorithm that can't be easily checked by integration tests (like service requires various mocks in various cases) then unit tests for services can be done.
Besides, in general, unit tests are way faster than Spring's tests. So (again subjective) my personal rule is: if you can gain the confidence in code with unit test - do it. If you need to check integration - go for integration test.