Mockito Mock vs Stub

1. Overview

In the world of unit testing, Mockito is a popular mocking framework that Java developers often use. A common source of confusion for many is the distinction between 'mocking' and 'stubbing'. This tutorial aims to clarify these concepts and demonstrate their application with Mockito.

2. Difference Between Mock and Stub

Mock: 

Purpose: To verify behavior. A mock is used to check if a certain method has been called with the right parameters. 

Behavior: Mocks don't have their behavior unless specified. By default, they return default values (like null, 0, etc.). 

With Mockito: You create a mock using Mockito.mock(ClassName.class)

Usage: You set expectations on a mock (using Mockito's when method) and later verify if those expectations were met using verify()

Stub: 

Purpose: To provide pre-determined behavior. A stub provides canned responses, irrespective of what input it gets. 

Behavior: Stubs have predefined behavior. For example, a stubbed method may always return the same value or throw an exception. 

With Mockito: You stub a method to return a specific value using when(...).thenReturn(...)

Usage: Useful when you want to isolate the unit of work from its collaborators or external dependencies.

3. Example Steps

1. Set up a new Maven project.

2. Add Mockito and JUnit 5 dependencies.

3. Create an interface and its implementation.

4. Write tests using Mockito and JUnit 5 demonstrating the difference between mocking and stubbing.

5. Run the tests.

4. Dependencies (Mockito and JUnit 5)

<!-- JUnit 5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>
<!-- Mockito Core -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.6.0</version>
    <scope>test</scope>
</dependency>

5. Code Program

// Define an interface
interface Service {
    String greet(String name);
}
// Implement the Service interface
class RealService implements Service {
    @Override
    public String greet(String name) {
        return "Hello, " + name;
    }
}
// Test class using Mockito and JUnit 5
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
public class ServiceTest {
    @Test
    public void mockServiceTest() {
        // Create a mock of the Service
        Service mockService = mock(Service.class);
        // Call greet method on mock
        mockService.greet("John");
        // Verify if greet method was called with the argument "John"
        verify(mockService).greet("John");
    }
    @Test
    public void stubServiceTest() {
        // Create a stub of the Service
        Service stubService = mock(Service.class);
        // Stub the greet method
        when(stubService.greet(anyString())).thenReturn("Hi there!");
        // Call greet method on stub
        String response = stubService.greet("John");
        // Assert that the stub returned the stubbed response
        assert(response.equals("Hi there!"));
    }
}

Output:

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

Code Explanation:

1. We begin by defining a Service interface and its implementation, RealService.

2. In mockServiceTest(), we mock the Service. The key here is to verify that methods are called with expected parameters using the verify() method.

3. In stubServiceTest(), we stub the Service using the when().thenReturn() approach. The purpose is to control the behavior of the service for the test's context. When the greet method is invoked, it returns the value we've stubbed ("Hi there!") instead of its real implementation.

4. The distinction is clear; mocks are about verifying interactions, while stubs are about providing controlled behavior.

6. Conclusion

Understanding the distinction between mocks and stubs is vital for effective unit testing. With Mockito, you can effortlessly create both mocks and stubs to ensure your tests are both thorough and isolated. While mocks are used to verify interactions, stubs control an object's behavior for the context of the test.

Comments