Mockito @Captor Example

1. Introduction

The @Captor annotation is used in Mockito to create an ArgumentCaptor instance. ArgumentCaptor is a powerful feature that allows us to capture argument values passed to methods so we can later make assertions on them. This can be especially useful when we want to verify the data being passed to methods without having access to that data directly within the test.

2. Example Steps

1. Define an interface and its implementation.

2. Define a service class that uses the interface.

3. Create a test class.

4. Within the test class, mock the interface and spy the service class.

5. Use the @Captor annotation to create an ArgumentCaptor.

6. Invoke methods in the service class that use the mocked interface.

7. Capture the arguments passed to the mocked interface using the ArgumentCaptor.

8. Make assertions on the captured arguments.

3. Mockito @Captor Example

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.verify;
import static org.junit.jupiter.api.Assertions.*;

interface Logger {
    void logMessage(String message);
}

class LoggingService {
    private final Logger logger;

    public LoggingService(Logger logger) {
        this.logger = logger;
    }

    public void logUrgentMessage(String message) {
        logger.logMessage("URGENT: " + message);
    }
}

public class LoggingServiceTest {
    @Mock
    Logger mockLogger;

    @InjectMocks
    LoggingService loggingService;

    @Captor
    ArgumentCaptor<String> stringArgumentCaptor;

    @Test
    public void testLogUrgentMessage() {
        MockitoAnnotations.initMocks(this);

        // Call logUrgentMessage in the service
        loggingService.logUrgentMessage("System failure!");

        // Capture the argument passed to mockLogger.logMessage
        verify(mockLogger).logMessage(stringArgumentCaptor.capture());

        // Assert the message passed to the logger
        assertEquals("URGENT: System failure!", stringArgumentCaptor.getValue());
    }
}

Output:

The test will pass, ensuring that the "URGENT: " prefix was correctly added to the message before it was logged.

4. Step By Step Explanation

1. We have an interface Logger and its implementation LoggingService. The LoggingService adds a prefix "URGENT: " to any message it logs.

2. In the LoggingServiceTest, we create a mock for the Logger interface using @Mock.

3. We also spy the LoggingService with @InjectMocks, which will use the mockLogger.

4. We declare an ArgumentCaptor for String type using @Captor annotation.

5. Inside the testLogUrgentMessage method, we call the logUrgentMessage of our spied loggingService.

6. Using the verify method, we ensure the logMessage method of our mockLogger was called, and capture its argument using the ArgumentCaptor.

7. Finally, we assert that the message passed to the logger had the correct prefix added.


Comments