liujie
2026-09-09 39f6fca28e3f78abe48f08e474ec011abb990b36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.tourguide.integration.wechat;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tourguide.common.exception.BusinessException;
import com.tourguide.config.properties.WechatMiniProgramProperties;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;
 
import java.time.Duration;
 
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
 
class WechatMiniProgramClientTest {
    private StringRedisTemplate redisTemplate;
    private ValueOperations<String, String> valueOperations;
    private MockRestServiceServer server;
    private WechatMiniProgramClient client;
 
    @BeforeEach
    @SuppressWarnings("unchecked")
    void setUp() {
        RestTemplate restTemplate = new RestTemplate();
        server = MockRestServiceServer.bindTo(restTemplate).build();
        redisTemplate = mock(StringRedisTemplate.class);
        valueOperations = mock(ValueOperations.class);
        when(redisTemplate.opsForValue()).thenReturn(valueOperations);
        when(valueOperations.get(anyString())).thenReturn(null);
 
        WechatMiniProgramProperties properties = new WechatMiniProgramProperties();
        properties.setAppId("test-app");
        properties.setAppSecret("test-secret");
        client = new WechatMiniProgramClient(properties, restTemplate, redisTemplate, new ObjectMapper());
    }
 
    @Test
    void shouldExchangeLoginAndPhoneCodes() {
        server.expect(requestTo("https://api.weixin.qq.com/sns/jscode2session?appid=test-app&secret=test-secret&js_code=login-code&grant_type=authorization_code"))
                .andRespond(withSuccess("{\"openid\":\"openid-1\",\"session_key\":\"session-key\"}", MediaType.TEXT_PLAIN));
        server.expect(requestTo("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=test-app&secret=test-secret"))
                .andRespond(withSuccess("{\"access_token\":\"access-token\",\"expires_in\":7200}", MediaType.TEXT_PLAIN));
        server.expect(requestTo("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=access-token"))
                .andExpect(content().json("{\"code\":\"phone-code\"}"))
                .andRespond(withSuccess("{\"errcode\":0,\"errmsg\":\"ok\",\"phone_info\":{\"purePhoneNumber\":\"13800138000\"}}", MediaType.TEXT_PLAIN));
 
        WechatPhoneAuthorization authorization = client.authorizePhoneLogin("login-code", "phone-code");
 
        assertThat(authorization.getOpenid()).isEqualTo("openid-1");
        assertThat(authorization.getMobile()).isEqualTo("13800138000");
        verify(valueOperations).set("tourguide:wechat:mini:access-token:test-app", "access-token", Duration.ofSeconds(6900));
        server.verify();
    }
 
    @Test
    void shouldReportWechatConfigurationError() {
        server.expect(requestTo("https://api.weixin.qq.com/sns/jscode2session?appid=test-app&secret=test-secret&js_code=login-code&grant_type=authorization_code"))
                .andRespond(withSuccess("{\"errcode\":40125,\"errmsg\":\"invalid appsecret\"}", MediaType.TEXT_PLAIN));
 
        assertThatThrownBy(() -> client.authorizePhoneLogin("login-code", "phone-code"))
                .isInstanceOf(BusinessException.class)
                .hasMessage("微信小程序 AppID 或 AppSecret 配置错误(微信错误码:40125)");
        server.verify();
    }
}