JUnit Mock: A Guide to Unit Testing with Mocks in Java

When it comes to testing in Java, JUnit has long been the go-to framework. It's fast, reliable, and integrates seamlessly with most build tools and IDEs. However, testing real-world applications often requires more than just writing simple test methods. You often need to isolate units of code and simulate the behavior of complex dependencies. That’s where mocking comes in.

In this blog, we’ll explore what mocking is, why it's useful, and how to implement it using JUnit mock with a popular mocking framework—Mockito.

 

What Is Mocking?

Mocking is a technique used in unit testing to replace real objects with fake (mock) objects that simulate the behavior of real components.

For example, consider a class that depends on an external service like a database, API, or file system. Instead of invoking the actual dependency in a unit test (which makes tests slower and brittle), you can mock the dependency and define expected behavior.

This helps ensure your unit test focuses only on the logic of the class being tested, not its dependencies.

 

Why Use Mocks in Unit Testing?

Here are key reasons why mocking is crucial:

  1. Isolation: Test only the unit under consideration.


  2. Speed: Avoid expensive operations like API calls or database access.


  3. Stability: Mocks are consistent and don’t depend on external systems.


  4. Verification: You can verify if methods were called and with what arguments.



 

Introduction to Mockito

While JUnit is used for writing tests, it doesn’t have built-in support for mocking. That’s where Mockito comes in.

Mockito is the most popular mocking framework in the Java ecosystem. It works well with JUnit and allows you to create and configure mock objects with ease.

Maven Dependency


To use Mockito with JUnit 5, add the following to your pom.xml:

xml

CopyEdit

<dependency>

  <groupId>org.mockito</groupId>

  <artifactId>mockito-core</artifactId>

  <version>5.3.1</version>

  <scope>test</scope>

</dependency>

 

Basic Mocking Example

Let’s say you have the following service and repository:

java

CopyEdit

public class UserRepository {

    public String findNameById(int id) {

        // Imagine this hits a real database

        return "John Doe";

    }

}

 

public class UserService {

    private UserRepository repository;

 

    public UserService(UserRepository repository) {

        this.repository = repository;

    }

 

    public String getUppercaseUserName(int id) {

        return repository.findNameById(id).toUpperCase();

    }

}

 

Test with Mockito Mock


java

CopyEdit

import static org.mockito.Mockito.*;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

 

public class UserServiceTest {

 

    @Test

    public void testGetUppercaseUserName() {

        // Create mock object

        UserRepository mockRepo = mock(UserRepository.class);

 

        // Define behavior

        when(mockRepo.findNameById(1)).thenReturn("jane doe");

 

        // Inject mock into service

        UserService service = new UserService(mockRepo);

 

        // Run test

        String result = service.getUppercaseUserName(1);

 

        // Assert

        assertEquals("JANE DOE", result);

 

        // Verify interaction

        verify(mockRepo).findNameById(1);

    }

}

 

Key Mockito Functions

  • mock(Class<T>): Creates a mock instance.


  • when(...).thenReturn(...): Defines what the mock should return.


  • verify(...): Checks if a method was called.


  • doThrow(...), doNothing(): Useful for testing exception scenarios.



 

Using @Mock and @InjectMocks

Mockito also provides annotations to simplify mocking.

java

CopyEdit

@ExtendWith(MockitoExtension.class)

public class UserServiceTest {

 

    @Mock

    private UserRepository mockRepo;

 

    @InjectMocks

    private UserService service;

 

    @Test

    public void testGetUppercaseUserName() {

        when(mockRepo.findNameById(1)).thenReturn("Jane");

 

        String result = service.getUppercaseUserName(1);

 

        assertEquals("JANE", result);

        verify(mockRepo).findNameById(1);

    }

}

 

This approach eliminates manual creation and injection of mock objects.

 

Common Mocking Scenarios

  • Return different values for different inputs using when(...).thenReturn(...).


  • Simulate exceptions using when(...).thenThrow(...).


  • Check call counts using verify(mock, times(n)).


  • Avoid real side effects such as API calls or DB writes in tests.



 

Best Practices

  1. Mock only what you own: Avoid mocking third-party classes unless necessary.


  2. Keep tests small and focused on a single behavior.


  3. Don’t overuse mocks—for integration or end-to-end testing, use real dependencies.


  4. Use clear naming for test methods and mocks to improve readability.



Conclusion

Mocking in unit tests is a critical skill for any Java developer. With JUnit and Mockito, you can write fast, reliable, and maintainable tests that validate your application logic in isolation.

Whether you're testing a simple method or a complex service with multiple dependencies, mocking gives you control and confidence in your codebase. It’s not just about avoiding external dependencies—it’s about writing robust tests that catch real bugs.

Read more- https://keploy.io/blog/community/simplifying-junit-test-stubs-and-mocking

Leave a Reply

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