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

SpringBootTest中如何Mock GraphServiceClient实现Azure AD B2C用户创建测试

如何Mock GraphServiceClient测试Azure AD B2C用户创建方法?

我在应用中实现了一个通过Microsoft Graph REST API在Azure AD B2C创建用户的Java方法,现在想要像使用RestTemplate时借助MockRestServiceServer那样,Mock GraphServiceClient来返回预设的用户对象进行测试。原方法代码如下:

public User createUser(User user) throws ClientException {
        final ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
                .clientId(clientId)
                .clientSecret(clientSecret)
                .tenantId(tenantId)
                .build();

        final TokenCredentialAuthProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(Arrays.asList(scope), clientSecretCredential);

        GraphServiceClient graphClient = GraphServiceClient.builder()
                .authenticationProvider(tokenCredentialAuthProvider)
                .buildClient();

        user.passwordPolicies = "DisablePasswordExpiration"; // optional
        PasswordProfile passwordProfile = new PasswordProfile();
        passwordProfile.forceChangePasswordNextSignIn = true; // false if the user does not need to change password
        passwordProfile.password = "xWwvJ]6NMw+bWH-d";
        user.passwordProfile = passwordProfile;

        return graphClient.users()
                .buildRequest()
                .post(user);
    }

解决方案

1. 重构代码,依赖注入GraphServiceClient

原方法直接在内部创建GraphServiceClient,无法直接Mock。需要将GraphServiceClient的创建逻辑抽离,通过依赖注入的方式传入类中:

重构后的业务类

import com.microsoft.graph.models.User;
import com.microsoft.graph.requests.GraphServiceClient;
import com.microsoft.graph.http.ClientException;

public class UserService {
    private final GraphServiceClient graphServiceClient;

    // 通过构造函数注入GraphServiceClient
    public UserService(GraphServiceClient graphServiceClient) {
        this.graphServiceClient = graphServiceClient;
    }

    public User createUser(User user) throws ClientException {
        user.passwordPolicies = "DisablePasswordExpiration";
        PasswordProfile passwordProfile = new PasswordProfile();
        passwordProfile.forceChangePasswordNextSignIn = true;
        passwordProfile.password = "xWwvJ]6NMw+bWH-d";
        user.passwordProfile = passwordProfile;

        return graphServiceClient.users()
                .buildRequest()
                .post(user);
    }
}

配置类(Spring环境下)

将GraphServiceClient注册为Bean,供业务类注入:

import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import com.microsoft.graph.requests.GraphServiceClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;

@Configuration
public class GraphClientConfig {
    @Value("${azure.client-id}")
    private String clientId;

    @Value("${azure.client-secret}")
    private String clientSecret;

    @Value("${azure.tenant-id}")
    private String tenantId;

    @Value("${graph.scope}")
    private String scope;

    @Bean
    public GraphServiceClient graphServiceClient() {
        ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
                .clientId(clientId)
                .clientSecret(clientSecret)
                .tenantId(tenantId)
                .build();

        TokenCredentialAuthProvider authProvider = new TokenCredentialAuthProvider(Arrays.asList(scope), clientSecretCredential);

        return GraphServiceClient.builder()
                .authenticationProvider(authProvider)
                .buildClient();
    }
}

2. 使用Mockito编写Mock测试

通过Mockito MockGraphServiceClient及其链式调用的对象,预设调用行为:

import com.microsoft.graph.models.User;
import com.microsoft.graph.requests.GraphServiceClient;
import com.microsoft.graph.requests.UserRequest;
import com.microsoft.graph.requests.UserRequestBuilder;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    @Mock
    private GraphServiceClient graphServiceClient;

    @Mock
    private UserRequestBuilder userRequestBuilder;

    @Mock
    private UserRequest userRequest;

    @InjectMocks
    private UserService userService;

    @Test
    void createUser_ShouldReturnMockUser() throws Exception {
        // 1. 构建预设的请求参数和返回对象
        User inputUser = new User();
        inputUser.displayName = "Test User";
        inputUser.userPrincipalName = "test@example.com";

        User mockResponseUser = new User();
        mockResponseUser.id = "mock-user-id-123";
        mockResponseUser.displayName = "Test User";

        // 2. 设定Mock的链式调用行为
        when(graphServiceClient.users()).thenReturn(userRequestBuilder);
        when(userRequestBuilder.buildRequest()).thenReturn(userRequest);
        when(userRequest.post(inputUser)).thenReturn(mockResponseUser);

        // 3. 调用业务方法
        User result = userService.createUser(inputUser);

        // 4. 断言结果
        assertNotNull(result);
        assertEquals("mock-user-id-123", result.id);
        assertEquals("Test User", result.displayName);

        // 验证调用次数
        verify(graphServiceClient, times(1)).users();
        verify(userRequestBuilder, times(1)).buildRequest();
        verify(userRequest, times(1)).post(inputUser);
    }
}

关键说明

  • 由于GraphServiceClient的调用是链式的(users() -> buildRequest() -> post()),需要依次Mock每个环节的对象(UserRequestBuilder、UserRequest)
  • 重构后通过依赖注入解耦了GraphServiceClient的创建与业务逻辑,让测试可以轻松替换为Mock对象
  • 测试中可以完全模拟Graph API的返回结果,无需依赖真实的Azure环境

内容的提问来源于stack exchange,提问作者Aldo Inácio da Silva

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:27:38