Skip to content
Advertisement

Spring Boot service layer: Unit or Integration tests?

I have a service:

@Service
@Transactional
@RequiredArgsConstructor
public class BookService {

    private final BookRepository bookRepository;

    public Book findOne(Long id) {
        return bookRepository.findById(id).orElse(null);
    }

    public Book getOne(Long id) {
        return bookRepository.findById(id)
                .orElseThrow(() -> new BadRequestAlertException("entity-not-found", ("Entity with id: " + id + " not found!")));
    }

    public List<Book> getAll() {
        return bookRepository.findAll();
    }

    public Book save(Book book) {
        return bookRepository.save(book);
    }

}

I have written Integration tests for both database (BookRepository) and controller layer (BookController which uses BookService). I can’t find anywhere examples of integration tests for service layer. If I write unit tests properly, is there any use case for writting integration tests for it? As far as I can tell (it’s not a rule, but common use cases):

  • Controller – Integration tests
  • Service – Unit tests
  • Repository – Integration tests

Advertisement

Answer

OK, so here’s how you can think of it …

  1. It makes zero sense to write unit tests for repositories, they are only ever covered by integration tests. The choice to use an in-memory DB or a proper DB from a Docker container depends on the circumstances, but generally I’d go for a DB in a Docker container, since H2 (even with say postgres dialect) is not a complete copy of the Postgres DB. Therefore, the tests might run, but the app will crash in production.

  2. For controllers, you might want to have a mix of unit and integration tests. Test the majority of controller stuff using the MockMvc class. And the most critical scenarios are covered by integration tests to test the whole vertical ( 3 layered ) slice of functionality.

  3. Now we get to the services part. If your service has complicated business logic, which you want to validate, then it must be covered by unit tests, so that you can do a lot of checks is a small amount of time. Also, it makes sense to cover some of the most basic scenarios by integration tests. In specifically your case, the business logic inside the service layer is extremely simple, so I’d go for just the integration tests. If and when it gets more complicated, you can add also some unit tests, where you mock out the repository classes to have blazing fast test times and being able to make a lot of check without slowing down the CI pipeline for everyone on the project.

In general, try to always follow the test pyramid pattern and use the best possible testing libraries provided by the Spring Boot ecosystem.

Advertisement