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

Mock和单元测试Microsoft Graph API获取用户列表:空引用错误与Setup用法

问题分析与解决方法

现有测试代码的问题

  1. 空引用错误原因:mockGraphClient.Setup(g => g.Users.Request())中,g.Users未被Mock,直接访问会返回null,触发空引用异常。
  2. 类型不匹配:ReturnsAsync(users)返回单个User对象,但GetAsync()实际返回的是IGraphServiceUsersCollectionPage类型,类型完全不兼容。
  3. 测试对象偏差:测试中直接调用graphClient.Users.Request().GetAsync(),而非你封装的业务方法GetUsersAsync(),没有覆盖实际业务逻辑的测试场景。

修正后的测试实现步骤

1. 构造模拟的用户集合页

需要创建IGraphServiceUsersCollectionPage的Mock实例,用来承载测试用的用户列表:

// 构造测试用的用户数据
var testUsers = new List<User>
{
    new User { Id = "1", DisplayName = "test", GivenName = "test2", Surname = "test3" },
    new User { Id = "2", DisplayName = "Alice", GivenName = "Alice", Surname = "Smith" }
};

// Mock集合页对象,返回测试用户列表
var mockUsersPage = new Mock<IGraphServiceUsersCollectionPage>();
mockUsersPage.Setup(p => p.CurrentPage).Returns(testUsers);

2. 分层Mock GraphClient的链式调用

Graph SDK的调用是链式结构,需要逐层Mock每个节点,避免空引用:

var mockAuthProvider = new Mock<IAuthenticationProvider>();
var mockHttpProvider = new Mock<IHttpProvider>();
var mockGraphClient = new Mock<GraphServiceClient>(mockAuthProvider.Object, mockHttpProvider.Object);

// 1. Mock Users属性,返回集合请求构建器
var mockUsersCollectionBuilder = new Mock<IGraphServiceUsersCollectionRequestBuilder>();
mockGraphClient.Setup(g => g.Users).Returns(mockUsersCollectionBuilder.Object);

// 2. Mock Request()方法,返回集合请求对象
var mockUsersRequest = new Mock<IGraphServiceUsersCollectionRequest>();
mockUsersCollectionBuilder.Setup(u => u.Request(It.IsAny<IEnumerable<Option>>()))
                   .Returns(mockUsersRequest.Object);

// 3. Mock Select/OrderBy方法,返回自身以维持链式调用
mockUsersRequest.Setup(r => r.Select(It.IsAny<string>()))
                .Returns(mockUsersRequest.Object);
mockUsersRequest.Setup(r => r.OrderBy(It.IsAny<string>()))
                .Returns(mockUsersRequest.Object);

// 4. Mock GetAsync(),返回预先构造的模拟集合页
mockUsersRequest.Setup(r => r.GetAsync(CancellationToken.None))
                .ReturnsAsync(mockUsersPage.Object);

3. 测试你的业务方法

假设你的业务类名为UserService,注入GraphServiceClient,测试时传入Mock实例:

[TestMethod]
public async Task GetUsersAsync_Success_ReturnsExpectedUsers()
{
    // 实例化业务类,传入Mock的GraphClient
    var userService = new UserService(mockGraphClient.Object);

    // Act:调用业务方法
    var result = await userService.GetUsersAsync();

    // Assert:验证返回结果
    Assert.AreEqual(2, result.CurrentPage.Count());
    var firstUser = result.CurrentPage.First();
    Assert.AreEqual("1", firstUser.Id);
    Assert.AreEqual("test", firstUser.DisplayName);

    // 验证链式调用是否符合预期
    mockUsersRequest.Verify(r => r.Select(It.Is<string>(s => s.Contains("Id") && s.Contains("DisplayName"))), Times.Once);
    mockUsersRequest.Verify(r => r.OrderBy("DisplayName"), Times.Once);
    mockUsersRequest.Verify(r => r.GetAsync(CancellationToken.None), Times.Once);
}

关键注意点

  • 链式调用Mock规则:Graph SDK的每个链式方法(如Select/OrderBy)都需要Mock返回自身,否则链式调用会中断并触发空引用。
  • 严格类型匹配:必须确保返回值是IGraphServiceUsersCollectionPage类型,不能用单个User对象替代。
  • 聚焦业务逻辑:测试目标应该是你封装的业务方法,而非直接测试GraphClient,这样才能验证业务代码的正确性。

内容的提问来源于stack exchange,提问作者Tim Whatley

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:05:37