如何在测试中Stub Google OAuth令牌刷新的响应?
解决Google API令牌刷新请求Stub问题
问题背景
使用com.google.api.services.gmail.Gmail发送邮件时,测试触发sendEmail(Message message)方法,因用户令牌过期,.execute()会发起令牌刷新请求POST https://oauth2.googleapis.com/token。由于该URL在Google API库中硬编码,无法通过替换域名的方式用WireMock Stub响应,需其他可行方案。
可行方案
方案1:使用Google API Client官方Mock HTTP传输
Google API Client库自带MockHttpTransport,可直接拦截并模拟所有HTTP请求,包括令牌刷新请求。
步骤:
- 创建
MockHttpTransport实例,自定义请求处理逻辑,匹配POST https://oauth2.googleapis.com/token请求并返回模拟的令牌响应。 - 将该
MockHttpTransport配置到Gmail客户端的初始化流程中。
代码示例:
// 构建Mock HTTP传输,处理令牌刷新请求 MockHttpTransport mockTransport = new MockHttpTransport() { @Override public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { if ("POST".equals(method) && url.equals("https://oauth2.googleapis.com/token")) { return new MockLowLevelHttpRequest() { @Override public LowLevelHttpResponse execute() throws IOException { MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); response.setStatusCode(200); response.setContentType("application/json"); // 返回模拟的刷新令牌响应 response.setContent("{\"access_token\":\"new-mock-token\",\"expires_in\":3600}"); return response; } }; } // 其他请求可根据需要处理,或抛出异常 throw new IOException("Unexpected request: " + method + " " + url); } }; // 初始化Gmail客户端时使用Mock传输 Gmail gmail = new Gmail.Builder(mockTransport, JacksonFactory.getDefaultInstance(), credential) .setApplicationName("Your-App-Name") .build();
方案2:通过JVM系统代理拦截请求到WireMock
即使URL硬编码,也可通过设置JVM系统代理,将所有HTTPS请求转发到WireMock服务,由WireMock处理令牌刷新请求。
步骤:
- 启动WireMock服务,配置对
POST /token请求的Stub响应。 - 在测试代码启动前设置JVM系统代理:
System.setProperty("https.proxyHost", "localhost"); System.setProperty("https.proxyPort", "8080"); // WireMock监听端口
- 注意:需处理WireMock的HTTPS证书问题,可生成自签名证书并配置JVM信任,或让WireMock使用HTTP模式(仅测试环境可用)。
方案3:使用Mockito Spy替换HTTP请求逻辑
通过Mockito Spy替换Google API库中HttpTransport的实现,拦截令牌刷新请求并返回模拟响应。
代码示例:
// 获取真实的HttpTransport实例 HttpTransport realTransport = Gmail.DEFAULT_TRANSPORT; // Spy该实例,拦截buildRequest方法 HttpTransport spyTransport = Mockito.spy(realTransport); Mockito.when(spyTransport.buildRequest(Mockito.eq("POST"), Mockito.eq("https://oauth2.googleapis.com/token"))) .thenAnswer(invocation -> { MockLowLevelHttpRequest mockRequest = new MockLowLevelHttpRequest(); mockRequest.setResponse(new MockLowLevelHttpResponse() {{ setStatusCode(200); setContentType("application/json"); setContent("{\"access_token\":\"mock-refreshed-token\",\"expires_in\":3600}"); }}); return mockRequest; }); // 使用Spy后的传输初始化Gmail客户端 Gmail gmail = new Gmail.Builder(spyTransport, JacksonFactory.getDefaultInstance(), credential) .setApplicationName("Your-App-Name") .build();
内容的提问来源于stack exchange,提问作者Olesia Ilchuk
相关产品推荐
相关产品推荐

