← Back to list

Unit Testing in Spring Boot with JUnit and Mockito

Unit testing is a critical part of building reliable and maintainable Spring Boot applications. By writing unit tests, developers can…

Didin Jamaludin in Stackademic · 2025-12-29 11:07 · 0 claps · 12.9 min read
#spring-boot #unit-testing #junit #mockito #backend-testing
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Unit Testing in Spring Boot with JUnit and Mockito

Unit testing is a critical part of building reliable and maintainable Spring Boot applications. By writing unit tests, developers can verify that individual components-such as services, controllers, and utility classes-work as expected in isolation.

In the Spring Boot ecosystem, unit testing is commonly done using JUnit 5 as the testing framework and Mockito as the mocking library. Together, they allow you to test application logic without relying on real databases, external services, or full application context startup.

In this tutorial, you’ll learn how to write clean, effective unit tests in Spring Boot using JUnit and Mockito. We’ll cover everything from basic test setup to testing service and controller layers, along with best practices used in real-world projects.

By the end of this guide, you’ll be able to:

  • Write unit tests for Spring Boot services and controllers
  • Mock dependencies using Mockito
  • Understand when to use @WebMvcTest vs @SpringBootTest
  • Structure your tests for readability and maintainability

Let’s start by setting up a Spring Boot project with the necessary testing dependencies.

Before writing any unit tests, we need a Spring Boot project that is properly configured for testing with JUnit 5 and Mockito. Spring Boot makes this setup straightforward by providing built-in testing support.

1. Creating a Spring Boot Project

You can create a new Spring Boot project using Spring Initializr or your preferred IDE (IntelliJ IDEA, Eclipse, VS Code).

Recommended configuration:

This tutorial focuses on unit testing, so a simple REST API structure is more than enough.

2. Understanding spring-boot-starter-test

Spring Boot provides a dedicated testing starter:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

This single dependency includes everything we need for unit testing:

  • JUnit Jupiter (JUnit 5) — test framework
  • Mockito — mocking dependencies
  • AssertJ — fluent assertions
  • Hamcrest — matcher-based assertions
  • Spring Test — Spring-specific testing utilities
  • JSONassert & JsonPath — JSON testing support

👉 By default, Spring Boot excludes JUnit 4, so you don’t need to remove anything manually.

3. Verifying the Maven pom.xml

Your pom.xml should contain at least the following testing dependency:

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>

If you want to explicitly use the latest Mockito version, you can add:

<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency>

⚠️ This is optional-Spring Boot already manages Mockito versions for you.

4. Project Structure for Testing

Spring Boot follows a clear convention for test placement.

src ├── main │ └── java │ └── com.example.demo │ ├── controller │ ├── service │ ├── repository │ └── DemoApplication.java └── test └── java └── com.example.demo ├── controller ├── service └── DemoApplicationTests.java

Key points:

  • Tests live under src/test/java
  • The package structure mirrors src/main/java
  • Each layer (controller, service) has its own test class

5. Creating a Sample Service to Test

Let’s add a simple service that we’ll use in later sections.

@Service public class CalculatorService { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; } }

This small service is perfect for demonstrating unit testing fundamentals without distractions.

6. Running Tests in Spring Boot

Spring Boot automatically detects and runs tests that:

You can run tests using:

If everything is configured correctly, Maven should report BUILD SUCCESS.

Understanding JUnit 5 Basics

JUnit 5 is the modern testing framework used by Spring Boot for writing and running unit tests. In this section, we’ll cover the essential JUnit 5 concepts you need to write clean, readable, and effective unit tests.

1. What Is JUnit 5?

JUnit 5 is a complete rewrite of JUnit with a modular architecture. It consists of three main parts:

  • JUnit Platform — The foundation that launches testing frameworks on the JVM
  • JUnit Jupiter — The API for writing tests and extensions (what we use most)
  • JUnit Vintage — Support for running legacy JUnit 4 tests (optional)

Spring Boot uses JUnit Jupiter by default, so you can start writing JUnit 5 tests immediately.

2. Creating Your First JUnit 5 Test

Let’s write a simple unit test for the CalculatorService we created earlier.

Create a new test class under src/test/java:

class CalculatorServiceTest { private CalculatorService calculatorService; @BeforeEach void setUp() { calculatorService = new CalculatorService(); } @Test void shouldAddTwoNumbers() { int result = calculatorService.add(5, 3); assertEquals(8, result); } }

✔️ This is a pure unit test:

3. Core JUnit 5 Annotations

JUnit 5 provides several useful annotations:

Example:

@BeforeAll static void initAll() { System.out.println("Runs once before all tests"); } @AfterEach void tearDown() { System.out.println("Runs after each test"); }

4. Assertions in JUnit 5

Assertions are used to verify expected results.

Common assertions:

assertEquals(expected, actual); assertNotNull(object); assertTrue(condition); assertFalse(condition); assertThrows(Exception.class, executable);

Example with exception testing:

@Test void shouldThrowExceptionWhenDividingByZero() { assertThrows(ArithmeticException.class, () -> { int result = 10 / 0; }); }

JUnit 5 also supports lambda-based assertions, which improve readability.

5. Display Names for Readable Tests

You can use @DisplayName to make the test output more descriptive.

@Test @DisplayName("Add two numbers and return the correct result") void addTwoNumbers() { int result = calculatorService.add(2, 3); assertEquals(5, result); }

This is especially useful in larger projects and CI pipelines.

6. Grouping Tests with Nested Classes

JUnit 5 allows grouping related tests using @Nested.

@Nested class AdditionTests { @Test void shouldAddPositiveNumbers() { assertEquals(10, calculatorService.add(5, 5)); } @Test void shouldAddNegativeNumbers() { assertEquals(-4, calculatorService.add(-2, -2)); } }

This helps organize tests logically and improves readability.

7. Naming Conventions and Best Practices

Recommended test naming patterns:

Example:

shouldReturnSumWhenAddingTwoNumbers()

Follow the Arrange — Act — Assert (AAA) pattern:

8. When NOT to Use Spring in Unit Tests

For true unit tests:

JUnit + plain Java objects = fast and reliable tests

We’ll introduce Spring-specific testing only when needed.

Introduction to Mockito

In real-world Spring Boot applications, classes rarely work in isolation. Services often depend on repositories, external APIs, or other services. Mockito allows us to replace those dependencies with mock objects, so we can test business logic without relying on real implementations.

1. What Is Mockito?

Mockito is a popular Java mocking framework used to:

With Mockito, you can focus on what your class does, not what its dependencies do.

2. Why Mockito Is Essential for Unit Testing

Without mocking, unit tests can:

Mockito solves this by allowing you to:

👉 Rule of thumb: If a class depends on something outside itself, mock it.

3. Adding Mockito (Already Included)

Spring Boot includes Mockito via:

spring-boot-starter-test

So no extra setup is required for most projects.

4. Creating a Service with a Dependency

Let’s create a simple service that depends on a repository.

@Repository public interface UserRepository { Optional<User> findById(Long id); }
@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public User getUserById(Long id) { return userRepository.findById(id) .orElseThrow(() -> new RuntimeException("User not found")); } }

5. Writing a Unit Test with Mockito

Now let’s write a unit test using Mockito.

@ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService; @Test void shouldReturnUserWhenUserExists() { User user = new User(1L, "John"); when(userRepository.findById(1L)) .thenReturn(Optional.of(user)); User result = userService.getUserById(1L); assertEquals("John", result.getName()); } }

What’s happening here?

6. Verifying Interactions

Mockito can verify that methods are called as expected.

@Test void shouldCallRepositoryOnce() { when(userRepository.findById(1L)) .thenReturn(Optional.of(new User(1L, "John"))); userService.getUserById(1L); verify(userRepository, times(1)).findById(1L); }

Useful verification methods:

7. Testing Exceptions with Mockito

You can also test exception scenarios.

@Test void shouldThrowExceptionWhenUserNotFound() { when(userRepository.findById(1L)) .thenReturn(Optional.empty()); assertThrows(RuntimeException.class, () -> { userService.getUserById(1L); }); }

8. Stubbing vs Mocking (Quick Concept)

Example:

when(repository.save(any())) .thenThrow(new RuntimeException("DB error"));

9. Common Mockito Pitfalls

❌ Forgetting @ExtendWith(MockitoExtension.class) ❌ Mixing Mockito with@SpringBootTest unnecessarily ❌ Mocking the class under test ❌ Overusing verify() instead of asserting behavior

Unit Testing the Service Layer with Mockito

The service layer contains your core business logic. This makes it the most important layer to test thoroughly. In this section, you’ll learn how to write clean, fast, and isolated unit tests for Spring Boot services using JUnit 5 and Mockito.

1. What Should Be Tested in the Service Layer?

Service unit tests should focus on:

  • Business rules and calculations
  • Conditional logic (if/else, validations)
  • Interactions with repositories
  • Exception handling

They should not:

2. Example Domain Model

Let’s extend our example with a simple User entity.

public class User { private Long id; private String name; private String email; // constructors, getters, setters }

3. Repository Interface (Dependency)

@Repository public interface UserRepository { Optional<User> findById(Long id); User save(User user); boolean existsByEmail(String email); }

4. Service Implementation

@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public User createUser(User user) { if (userRepository.existsByEmail(user.getEmail())) { throw new IllegalArgumentException("Email already exists"); } return userRepository.save(user); } public User getUserById(Long id) { return userRepository.findById(id) .orElseThrow(() -> new RuntimeException("User not found")); } }

5. Setting Up the Service Test Class

@ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService; }

✔️ No Spring context ✔️ Fast execution ✔️ Fully isolated tests

6. Testing a Successful Service Method

Key points:

7. Testing, Validation, and Business Rules

✔️ Ensures business rule enforcement ✔️ Verifies no unwanted interactions

8. Testing Exception Handling

@Test void shouldThrowExceptionWhenUserNotFound() { when(userRepository.findById(1L)) .thenReturn(Optional.empty()); Throwable exception = assertThrows(RuntimeException.class, () -> { userService.getUserById(1L); }); assertNotNull(exception); }

9. Using Argument Matchers

Mockito provides argument matchers for flexibility.

when(userRepository.save(any(User.class))) .thenReturn(user);

Common matchers:

⚠️ Rule: If you use a matcher for one argument, use matchers for all.

10. Arrange — Act — Assert Pattern (AAA)

Refactor tests for clarity:

@Test void shouldReturnUserById() { // Arrange User user = new User(1L, "John", "[email protected]"); when(userRepository.findById(1L)) .thenReturn(Optional.of(user)); // Act User result = userService.getUserById(1L); // Assert assertEquals("John", result.getName()); }

11. Common Mistakes in Service Layer Testing

❌ Mocking the service itself ❌ Using@Autowired in unit tests ❌ Using real repositories ❌ Overusing verify() instead of assertions

Unit Testing REST Controllers in Spring Boot

REST controllers handle HTTP requests and responses. When unit testing controllers, the goal is to verify request mapping, input validation, HTTP status codes, and response bodies -without starting a full server or loading the entire Spring context.

Spring Boot provides excellent tools for this through **@WebMvcTest and MockMvc**.

1. What Should Controller Unit Tests Cover?

Controller tests should verify:

  • Correct URL mapping and HTTP methods
  • Request/response JSON structure
  • HTTP status codes
  • Interaction with the service layer

They should not:

2. Sample REST Controller

Let’s create a simple UserController.

package com.example.demo.controller; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.example.demo.entity.User; import com.example.demo.service.UserService; @RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @PostMapping public ResponseEntity<User> createUser(@RequestBody User user) { User savedUser = userService.createUser(user); return ResponseEntity.status(HttpStatus.CREATED).body(savedUser); } @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { User user = userService.getUserById(id); return ResponseEntity.ok(user); } }

3. Using @WebMvcTest

@WebMvcTest loads only the web layer (controllers, filters, converters).

package com.example.demo.controller; import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.web.servlet.MockMvc; import com.example.demo.service.UserService; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(UserController.class) class UserControllerTest { @Autowired private MockMvc mockMvc; @Mock private UserService userService; }

Why this works:

  • MockMvc simulates HTTP requests
  • @MockBean injects a mock into the Spring context
  • No full application startup

4. Testing GET Endpoints

✔️ Verifies status ✔️ Verifies JSON fields ✔️ No real service call

5. Testing POST Endpoints

@Test void shouldCreateUser() throws Exception { User user = new User(null, "John", "[email protected]"); User savedUser = new User(1L, "John", "[email protected]"); when(userService.createUser(any(User.class))) .thenReturn(savedUser); mockMvc.perform(post("/api/users") .contentType(MediaType.APPLICATION_JSON) .content(""" { "name": "John", "email": "[email protected]" } """)) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id").value(1)) .andExpect(jsonPath("$.name").value("John")); }

6. Testing Validation Errors (Optional)

If your controller uses validation:

@PostMapping public ResponseEntity<User> createUser(@Valid @RequestBody User user) { return ResponseEntity.status(HttpStatus.CREATED) .body(userService.createUser(user)); }

Test invalid input:

@Test void shouldReturnBadRequestForInvalidInput() throws Exception { mockMvc.perform(post("/api/users") .contentType(MediaType.APPLICATION_JSON) .content(""" { "email": "invalid" } """)) .andExpect(status().isBadRequest()); }

7. Verifying Service Interaction

8. @WebMvcTest vs @SpringBootTest

👉 Use @WebMvcTest whenever possible for controller tests.

9. Common Controller Testing Mistakes

❌ Using @SpringBootTest for simple controller tests ❌ Forgetting@MockBean for service dependencies ❌ Testing business logic in controllers ❌ Skipping JSON response validation

MockMvc for Controller Testing (GET, POST, PUT, DELETE)

MockMvc allows you to test Spring MVC controllers by simulating HTTP requests and validating responses-without starting a real server. In this section, we'll cover how to test all common HTTP methods: GET, POST, PUT, and DELETE.

1. What Is MockMvc?

MockMvc is part of Spring Test and provides:

  • A fluent API for performing HTTP requests
  • Full support for JSON request/response validation
  • Integration with @WebMvcTest

It is ideal for controller unit tests.

2. Sample REST Controller (CRUD)

@RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { return ResponseEntity.ok(userService.getUserById(id)); } @PostMapping public ResponseEntity<User> createUser(@RequestBody User user) { return ResponseEntity .status(HttpStatus.CREATED) .body(userService.createUser(user)); } @PutMapping("/{id}") public ResponseEntity<User> updateUser( @PathVariable Long id, @RequestBody User user) { return ResponseEntity.ok(userService.updateUser(id, user)); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteUser(id); return ResponseEntity.noContent().build(); } }

3. Test Class Setup

@WebMvcTest(UserController.class) class UserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; }

4. Testing GET Requests

@Test void shouldGetUserById() throws Exception { User user = new User(1L, "John", "[email protected]"); when(userService.getUserById(1L)).thenReturn(user); mockMvc.perform(get("/api/users/1")) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1)) .andExpect(jsonPath("$.name").value("John")); }

✔️ Verifies HTTP 200 ✔️ Validates JSON fields

5. Testing POST Requests

✔️ Verifies HTTP 201 ✔️ Tests request body parsing

6. Testing PUT Requests

✔️ Verifies HTTP 200 ✔️ Tests path variables + request body

7. Testing DELETE Requests

@Test void shouldDeleteUser() throws Exception { doNothing().when(userService).deleteUser(1L); mockMvc.perform(delete("/api/users/1")) .andExpect(status().isNoContent()); verify(userService).deleteUser(1L); }

✔️ Verifies HTTP 204 ✔️ Confirms service interaction

8. Testing Error Responses

Example: user not found.

@Test void shouldReturnNotFoundWhenUserDoesNotExist() throws Exception { when(userService.getUserById(1L)) .thenThrow(new RuntimeException("User not found")); mockMvc.perform(get("/api/users/1")) .andExpect(status().isInternalServerError()); }

💡 In real apps, map exceptions to HTTP codes using @ControllerAdvice.

9. Standalone MockMvc Setup (Without Spring Context)

For pure unit tests:

@BeforeEach void setup() { mockMvc = MockMvcBuilders .standaloneSetup(new UserController(userService)) .build(); }

✔️ Fastest execution ✔️ No Spring context

10. Common MockMvc Pitfalls

❌ Forgetting contentType(MediaType.APPLICATION_JSON) ❌ Not testing response JSON ❌ Using@SpringBootTest unnecessarily ❌ Ignoring error scenarios

Testing with @SpringBootTest (When and When Not to Use It)

So far, we’ve focused on fast, isolated unit tests using JUnit, Mockito, and @WebMvcTest. In this section, we'll look at **@SpringBootTest, which is used for integration-style tests** in Spring Boot-and learn when it makes sense to use it and when it does not.

1. What Is @SpringBootTest?

@SpringBootTest tells Spring Boot to load the full application context, just like when the application starts normally.

This includes:

  • All @Configuration classes
  • Controllers, services, repositories
  • DataSource and JPA configuration
  • Security configuration (if present)
@SpringBootTest class ApplicationIntegrationTest { }

👉 This makes @SpringBootTest powerful-but also slower.

2. When Should You Use @SpringBootTest?

Use @SpringBootTest when you want to test:

✅ Bean wiring and dependency injection ✅ Application context startup ✅ Multiple layers working together ✅ Real database behavior (often with H2 or Testcontainers) ✅ Security configuration

Example use cases:

3. When NOT to Use @SpringBootTest

Avoid @SpringBootTest for:

❌ Pure unit tests ❌ Service logic tests ❌ Controller request mapping tests ❌ Simple validation tests

Why?

👉 Rule of thumb: If Mockito alone can test it, do NOT use@SpringBootTest.

4. Example: Full Context Test

@SpringBootTest class UserServiceIntegrationTest { @Autowired private UserService userService; @Test void contextLoads() { assertNotNull(userService); } }

This test verifies that:

5. Using @SpringBootTest with Web Environment

To start an embedded web server:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class UserControllerIntegrationTest { @LocalServerPort private int port; @Test void shouldStartServer() { assertTrue(port > 0); } }

Useful when testing:

6. @SpringBootTest with MockMvc

You can combine @SpringBootTest with MockMvc:

@SpringBootTest @AutoConfigureMockMvc class UserControllerIntegrationTest { @Autowired private MockMvc mockMvc; @Test void shouldReturnOk() throws Exception { mockMvc.perform(get("/actuator/health")) .andExpect(status().isOk()); } }

✔️ Loads full context ✔️ No real HTTP server ❌ Slower than@WebMvcTest

7. Replacing Beans with @MockBean

Even with @SpringBootTest, you can mock dependencies:

@SpringBootTest class UserServiceTest { @MockBean private UserRepository userRepository; @Autowired private UserService userService; }

✔️ Real Spring context ✔️ Controlled dependencies

8. Comparison: Testing Annotations

9. Common Mistakes with @SpringBootTest

❌ Using it for every test ❌ Mixing unit and integration tests ❌ Not isolating slow tests ❌ Ignoring test profiles

10. Best Practices

✔️ Keep unit tests and integration tests separate ✔️ Name integration tests clearly (*IT, *IntegrationTest) ✔️ Use@ActiveProfiles("test") ✔️ Combine with Testcontainers for databases

Best Practices for Spring Boot Unit Testing

Writing tests is not just about coverage-it’s about creating fast, reliable, and maintainable tests that help you ship better software with confidence. In this section, we’ll summarize proven best practices for unit testing Spring Boot applications using JUnit 5, Mockito, and Spring Test utilities.

1. Prefer Unit Tests Over Integration Tests

Unit tests should be your first line of defense.

✔️ Fast execution ✔️ Easy to debug ✔️ No infrastructure required

Use integration tests (@SpringBootTest) sparingly and only when necessary.

80/20 rule: ~80% unit tests, ~20% integration tests

2. Test One Thing at a Time

Each test should validate a single behavior.

❌ Bad:

void testCreateAndDeleteUser() { ... }

✔️ Good:

void shouldCreateUserSuccessfully() { ... } void shouldDeleteUserById() { ... }

Clear intent = easier maintenance.

3. Follow the Arrange-Act-Assert (AAA) Pattern

Structure every test clearly:

@Test void shouldReturnUserById() { // Arrange when(userRepository.findById(1L)) .thenReturn(Optional.of(user)); // Act User result = userService.getUserById(1L); // Assert assertEquals("John", result.getName()); }

This improves readability and consistency.

4. Use Descriptive Test Names

Test names should describe behavior, not implementation.

Recommended patterns:

Example:

shouldThrowExceptionWhenEmailAlreadyExists()

5. Avoid Loading the Spring Context Unnecessarily

❌ Don’t use:

✔️ Prefer:

Context loading slows tests and increases flakiness.

6. Mock Dependencies, Not the Class Under Test

✔️ Mock:

❌ Do NOT mock:

Your goal is to test real logic.

7. Verify Behavior, Not Implementation Details

❌ Overusing verify():

verify(repository).findById(1L); verify(repository).save(any());

✔️ Focus on results:

assertEquals("John", result.getName());

Use verify() only when interaction matters.

8. Keep Tests Independent

Each test must:

Avoid shared mutable state.

9. Use Test Profiles

Always separate test configuration:

@ActiveProfiles("test")

Use:

10. Organize Tests by Layer

Mirror your main package structure:

src/test/java ├── controller ├── service └── repository

This improves discoverability and clarity.

11. Use Parameterized Tests for Edge Cases

Reduce duplication with JUnit 5:

@ParameterizedTest @ValueSource(ints = {0, -1, -5}) void shouldRejectInvalidIds(int id) { assertThrows(IllegalArgumentException.class, () -> { service.getUserById(id); }); }

12. Run Tests Automatically

✔️ Run tests on every build ✔️ Integrate with CI/CD ✔️ Fail fast on broken tests

13. Common Anti-Patterns to Avoid

❌ Writing tests after bugs appear ❌ Massive test classes ❌ Asserting logs instead of behavior ❌ Ignoring failing tests

Tests should be trusted, not ignored.

14. Final Checklist

Before committing your tests, ask:

Conclusion and Next Steps

Unit testing is a fundamental skill for building robust, maintainable, and scalable Spring Boot applications. By combining JUnit 5 and Mockito, you can confidently test your application logic without relying on slow or fragile external dependencies.

In this tutorial, you learned how to:

  • Write pure unit tests using JUnit 5
  • Mock dependencies effectively with Mockito
  • Test service-layer business logic in isolation
  • Validate REST controllers using @WebMvcTest and MockMvc
  • Understand when to use (and avoid) @SpringBootTest
  • Apply best practices for fast, reliable, and readable tests

By following these patterns, your tests will run faster, fail less often, and provide meaningful feedback during development and CI/CD pipelines.

Next Steps

To continue improving your testing skills in Spring Boot, consider exploring:

  • Integration Testing with Testcontainers Test real databases and infrastructure safely using Docker-based containers.
  • Spring Security Testing Learn how to test secured endpoints with MockMvc and JWT authentication.
  • Repository Testing with @DataJpaTest Validate JPA queries and database mappings efficiently.
  • Contract Testing Use tools like Spring Cloud Contract to test service-to-service communication.
  • Test Coverage and Quality Gates Integrate JaCoCo and enforce coverage rules in CI pipelines.

Final Recommendation

Start small:

  1. Write unit tests for every new service
  2. Add controller tests for public APIs
  3. Introduce integration tests only when needed

This layered approach keeps your test suite fast, focused, and maintainable -exactly what modern Spring Boot projects need.

You can find the full source code on our GitHub.

That’s just the basics. If you need more deep learning about Spring Boot, you can take the following cheap course:

Thanks!

Originally published at https://www.djamware.com.


메타데이터
post_id
2cfdb9f34fc8
slug
unit-testing-in-spring-boot-with-junit-and-mockito-2cfdb9f34fc8
url
https://blog.stackademic.com/unit-testing-in-spring-boot-with-junit-and-mockito-2cfdb9f34fc8
canonical_url
https://blog.stackademic.com/unit-testing-in-spring-boot-with-junit-and-mockito-2cfdb9f34fc8
author_url
https://medium.com/@didinjamaludin
status
ok
fetched_at
2026-06-09 15:37:30