You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot(JUnit4+Mockito)下Mock Retrofit编写单元测试求助

JUnit4 + Mockito Unit Tests for Retrofit Gmail Token Extraction

Great question! Let's break down how to write unit tests for your extractGmail method using JUnit4 and Mockito. The goal is to isolate your method's logic by mocking all external dependencies (Retrofit components and the Google API interface), so we don't make real calls to Google's servers during testing.

Complete Test Class

Assuming your extractGmail method lives in a service class like TokenValidationService (replace this with your actual class name), here's the full test code:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import retrofit2.Call;
import retrofit2.Response;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class TokenValidationServiceTest {

    // Mock the Retrofit API interface to avoid real API calls
    @Mock
    private GoogleTokenValidatorAPI googleTokenValidatorAPI;

    // Inject mocked dependencies into the service under test
    @InjectMocks
    private TokenValidationService tokenValidationService; // Replace with your actual service class

    @Test
    public void extractGmail_ValidToken_ReturnsEmail() throws IOException {
        // 1. Setup test data
        String validToken = "valid-google-token-123";
        String expectedEmail = "john.doe@nineleaps.com";
        
        GmailDTO mockGmailResponse = new GmailDTO();
        mockGmailResponse.setEmail(expectedEmail);
        mockGmailResponse.setHd("nineleaps.com");

        // 2. Mock Retrofit's Call and Response objects
        Call<GmailDTO> mockCall = mock(Call.class);
        Response<GmailDTO> successfulResponse = Response.success(mockGmailResponse);

        // 3. Define mock behavior
        when(googleTokenValidatorAPI.authenticateUsingGmail(validToken)).thenReturn(mockCall);
        when(mockCall.execute()).thenReturn(successfulResponse);

        // 4. Run the method under test
        String actualEmail = tokenValidationService.extractGmail(validToken);

        // 5. Verify results and interactions
        assertEquals(expectedEmail, actualEmail);
        verify(googleTokenValidatorAPI, times(1)).authenticateUsingGmail(validToken);
        verify(mockCall, times(1)).execute();
    }

    @Test(expected = Unauthorized.class)
    public void extractGmail_UnsuccessfulApiResponse_ThrowsUnauthorized() throws IOException {
        // 1. Setup test data
        String invalidToken = "invalid-google-token-456";

        // 2. Mock an unsuccessful API response (e.g., 401 Unauthorized)
        Call<GmailDTO> mockCall = mock(Call.class);
        Response<GmailDTO> errorResponse = Response.error(401, null);

        // 3. Define mock behavior
        when(googleTokenValidatorAPI.authenticateUsingGmail(invalidToken)).thenReturn(mockCall);
        when(mockCall.execute()).thenReturn(errorResponse);

        // 4. Execute method (should throw exception)
        tokenValidationService.extractGmail(invalidToken);
    }

    @Test(expected = Unauthorized.class)
    public void extractGmail_WrongDomain_ThrowsUnauthorized() throws IOException {
        // 1. Setup test data
        String validTokenWrongDomain = "valid-token-wrong-domain-789";
        
        GmailDTO mockGmailResponse = new GmailDTO();
        mockGmailResponse.setEmail("jane.doe@otherdomain.com");
        mockGmailResponse.setHd("otherdomain.com");

        // 2. Mock successful response with wrong domain
        Call<GmailDTO> mockCall = mock(Call.class);
        Response<GmailDTO> successfulResponse = Response.success(mockGmailResponse);

        // 3. Define mock behavior
        when(googleTokenValidatorAPI.authenticateUsingGmail(validTokenWrongDomain)).thenReturn(mockCall);
        when(mockCall.execute()).thenReturn(successfulResponse);

        // 4. Execute method (should throw exception)
        tokenValidationService.extractGmail(validTokenWrongDomain);
    }

    @Test(expected = Unauthorized.class)
    public void extractGmail_NullResponseBody_ThrowsUnauthorized() throws IOException {
        // 1. Setup test data
        String tokenWithNullBody = "token-with-null-body-000";

        // 2. Mock successful response with null body (edge case)
        Call<GmailDTO> mockCall = mock(Call.class);
        Response<GmailDTO> nullBodyResponse = Response.success(null);

        // 3. Define mock behavior
        when(googleTokenValidatorAPI.authenticateUsingGmail(tokenWithNullBody)).thenReturn(mockCall);
        when(mockCall.execute()).thenReturn(nullBodyResponse);

        // 4. Execute method (should throw exception)
        tokenValidationService.extractGmail(tokenWithNullBody);
    }
}

Key Concepts Explained

  • @RunWith(MockitoJUnitRunner.class): Enables Mockito's annotation support for JUnit4, handling mock initialization automatically.
  • @Mock: Creates fake instances of GoogleTokenValidatorAPI, Call, and Response so we don't rely on real Retrofit or Google API functionality.
  • @InjectMocks: Automatically injects the mocked GoogleTokenValidatorAPI into your service class, eliminating the need for manual dependency setup.
  • Test Scenarios:
    • Valid Token: Tests the happy path where the API response is successful and the domain matches, returning the user's email.
    • Unsuccessful Response: Tests when the API returns an error (like 401), triggering the Unauthorized exception.
    • Wrong Domain: Tests when the response is valid but the hd (hosted domain) doesn't match "nineleaps.com".
    • Null Response Body: Covers an edge case where the API returns a successful status but no body, preventing a NullPointerException in your method.

Additional Tips

  • If Unauthorized is a runtime exception (not declared in extractGmail's throws clause), the @Test(expected = Unauthorized.class) annotation will still work correctly.
  • If your service uses constructor injection instead of field injection, Mockito will still handle @InjectMocks as long as the constructor parameters match the mocked fields.

内容的提问来源于stack exchange,提问作者Bhavesh jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 23:27:45