Comprehensive Guide to Testing Spring Boot Applications with JUnit and Mockito

3 min read

Comprehensive Guide to Testing Spring Boot Applications with JUnit and Mockito

Testing is an essential part of developing robust and maintainable Spring Boot applications. This guide walks you through writing unit and integration tests using JUnit 5 and Mockito, two of the most popular tools in the Java ecosystem.


Why Use JUnit and Mockito?

  • JUnit 5: Modern and flexible testing framework for Java.
  • Mockito: A powerful mocking library that allows you to isolate units of code and simulate dependencies.

Together, they enable fast, isolated, and automated testing of your application’s business logic.


Maven Dependencies

Add the following to your pom.xml:

<dependencies>
    <!-- Spring Boot Starter Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- Optional: If you want to use Mockito explicitly -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>5.2.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

spring-boot-starter-test already includes JUnit 5, Mockito, Hamcrest, and AssertJ.


Sample Spring Boot Application

Let’s say we’re building a simple service that manages books.

Book.java

public class Book {
    private Long id;
    private String title;
    private String author;

    // Constructors, Getters, Setters
}

BookRepository.java

@Repository
public class BookRepository {
    private final Map<Long, Book> books = new HashMap<>();

    public Book save(Book book) {
        books.put(book.getId(), book);
        return book;
    }

    public Optional<Book> findById(Long id) {
        return Optional.ofNullable(books.get(id));
    }
}

BookService.java

@Service
public class BookService {
    private final BookRepository repository;

    public BookService(BookRepository repository) {
        this.repository = repository;
    }

    public Book createBook(Book book) {
        return repository.save(book);
    }

    public Book getBook(Long id) {
        return repository.findById(id)
                         .orElseThrow(() -> new RuntimeException("Book not found"));
    }
}

Writing Unit Tests with JUnit and Mockito

Let’s write a unit test for the BookService.

BookServiceTest.java

@ExtendWith(MockitoExtension.class)
public class BookServiceTest {

    @Mock
    private BookRepository bookRepository;

    @InjectMocks
    private BookService bookService;

    @Test
    void testCreateBook() {
        Book book = new Book(1L, "1984", "George Orwell");

        when(bookRepository.save(book)).thenReturn(book);

        Book result = bookService.createBook(book);

        assertNotNull(result);
        assertEquals("1984", result.getTitle());
        verify(bookRepository, times(1)).save(book);
    }

    @Test
    void testGetBookFound() {
        Book book = new Book(1L, "Brave New World", "Aldous Huxley");

        when(bookRepository.findById(1L)).thenReturn(Optional.of(book));

        Book result = bookService.getBook(1L);

        assertEquals("Brave New World", result.getTitle());
    }

    @Test
    void testGetBookNotFound() {
        when(bookRepository.findById(2L)).thenReturn(Optional.empty());

        RuntimeException exception = assertThrows(RuntimeException.class, () -> {
            bookService.getBook(2L);
        });

        assertEquals("Book not found", exception.getMessage());
    }
}

Integration Testing with Spring Context

For integration tests, load the Spring context and test actual beans.

BookServiceIntegrationTest.java

@SpringBootTest
public class BookServiceIntegrationTest {

    @Autowired
    private BookService bookService;

    @Autowired
    private BookRepository bookRepository;

    @Test
    void testIntegrationCreateAndFetchBook() {
        Book book = new Book(100L, "Clean Code", "Robert C. Martin");

        bookService.createBook(book);

        Book fetched = bookService.getBook(100L);

        assertEquals("Clean Code", fetched.getTitle());
    }
}

Best Practices

  • Mock external dependencies in unit tests.
  • Use @SpringBootTest only when testing full application context.
  • Separate unit and integration tests in different source folders (/test/unit vs /test/integration).
  • Test expected exceptions with assertThrows.
  • Use descriptive method names (e.g., testGetBookNotFound_ThrowsException).

Illustration

Let me know if you’d like a visual diagram showing the flow between repository, service, and tests (JUnit + Mockito logos included).


Conclusion

Using JUnit and Mockito with Spring Boot makes testing efficient, readable, and maintainable. With the help of @Mock, @InjectMocks, and @SpringBootTest, you can test every layer of your application with precision.

🤞 Never miss a story from us, get weekly updates to your inbox!

Leave a Reply

Your email address will not be published. Required fields are marked *