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

如何使用Moq模拟Microsoft Graph SDK v5的GraphServiceClient进行单元测试?

使用Moq为Graph API相关方法搭建单元测试环境

核心思路

你要测试的方法依赖于Microsoft Graph SDK的客户端,而Graph SDK本身提供了全套抽象接口(无需自行定义),可以直接用Moq对这些接口进行Mock,模拟Graph API的返回结果,从而隔离外部依赖,专注测试业务逻辑。

步骤与代码示例

假设你的业务类名为WebinarService,构造函数注入IGraphServiceClient:

public class WebinarService
{
    private readonly IGraphServiceClient _client;

    public WebinarService(IGraphServiceClient client)
    {
        _client = client;
    }

    // 待测试的方法
    public async Task<List<VirtualEventWebinar>> GetMany(string title)
    {
        var result = await _client.Solutions.VirtualEvents.Webinars.GetAsync();
        return result?.Value != null
            ? result.Value.Where(x => x.DisplayName.Contains(title)).ToList()
            : [];
    }
}

测试用例编写

以下是覆盖全场景的单元测试代码(以xunit为例):

using Moq;
using Microsoft.Graph;
using Xunit;

public class WebinarServiceTests
{
    [Fact]
    public async Task GetMany_TitleMatches_ReturnsFilteredList()
    {
        // 准备测试数据
        var testWebinars = new List<VirtualEventWebinar>
        {
            new() { DisplayName = "Azure Webinar" },
            new() { DisplayName = "Office 365 Workshop" },
            new() { DisplayName = "Azure Developer Session" }
        };

        // Mock 接口响应
        var mockResponse = new Mock<IVirtualEventsWebinarsCollectionResponse>();
        mockResponse.Setup(r => r.Value).Returns(testWebinars);

        // Mock Webinars请求构建器的GetAsync方法
        var mockWebinarsBuilder = new Mock<IVirtualEventsWebinarsCollectionRequestBuilder>();
        mockWebinarsBuilder.Setup(b => b.GetAsync(It.IsAny<CancellationToken>()))
                           .ReturnsAsync(mockResponse.Object);

        // 逐层Mock上层依赖
        var mockVirtualEventsBuilder = new Mock<IVirtualEventsRequestBuilder>();
        mockVirtualEventsBuilder.Setup(b => b.Webinars).Returns(mockWebinarsBuilder.Object);

        var mockSolutionsBuilder = new Mock<ISolutionsRequestBuilder>();
        mockSolutionsBuilder.Setup(b => b.VirtualEvents).Returns(mockVirtualEventsBuilder.Object);

        var mockGraphClient = new Mock<IGraphServiceClient>();
        mockGraphClient.Setup(c => c.Solutions).Returns(mockSolutionsBuilder.Object);

        // 初始化被测服务
        var service = new WebinarService(mockGraphClient.Object);

        // 执行测试
        var result = await service.GetMany("Azure");

        // 断言结果
        Assert.Equal(2, result.Count);
        Assert.All(result, w => w.DisplayName.Contains("Azure"));
    }

    [Fact]
    public async Task GetMany_ResultIsNull_ReturnsEmptyList()
    {
        var mockWebinarsBuilder = new Mock<IVirtualEventsWebinarsCollectionRequestBuilder>();
        mockWebinarsBuilder.Setup(b => b.GetAsync(It.IsAny<CancellationToken>()))
                           .ReturnsAsync((IVirtualEventsWebinarsCollectionResponse)null);

        // 组装上层Mock
        var mockVirtualEventsBuilder = new Mock<IVirtualEventsRequestBuilder>();
        mockVirtualEventsBuilder.Setup(b => b.Webinars).Returns(mockWebinarsBuilder.Object);

        var mockSolutionsBuilder = new Mock<ISolutionsRequestBuilder>();
        mockSolutionsBuilder.Setup(b => b.VirtualEvents).Returns(mockVirtualEventsBuilder.Object);

        var mockGraphClient = new Mock<IGraphServiceClient>();
        mockGraphClient.Setup(c => c.Solutions).Returns(mockSolutionsBuilder.Object);

        var service = new WebinarService(mockGraphClient.Object);
        var result = await service.GetMany("Any Title");

        Assert.Empty(result);
    }

    [Fact]
    public async Task GetMany_ResultValueIsNull_ReturnsEmptyList()
    {
        var mockResponse = new Mock<IVirtualEventsWebinarsCollectionResponse>();
        mockResponse.Setup(r => r.Value).Returns((List<VirtualEventWebinar>)null);

        var mockWebinarsBuilder = new Mock<IVirtualEventsWebinarsCollectionRequestBuilder>();
        mockWebinarsBuilder.Setup(b => b.GetAsync(It.IsAny<CancellationToken>()))
                           .ReturnsAsync(mockResponse.Object);

        // 组装上层Mock
        var mockVirtualEventsBuilder = new Mock<IVirtualEventsRequestBuilder>();
        mockVirtualEventsBuilder.Setup(b => b.Webinars).Returns(mockWebinarsBuilder.Object);

        var mockSolutionsBuilder = new Mock<ISolutionsRequestBuilder>();
        mockSolutionsBuilder.Setup(b => b.VirtualEvents).Returns(mockVirtualEventsBuilder.Object);

        var mockGraphClient = new Mock<IGraphServiceClient>();
        mockGraphClient.Setup(c => c.Solutions).Returns(mockSolutionsBuilder.Object);

        var service = new WebinarService(mockGraphClient.Object);
        var result = await service.GetMany("Any Title");

        Assert.Empty(result);
    }

    [Fact]
    public async Task GetMany_NoMatchingTitles_ReturnsEmptyList()
    {
        var testWebinars = new List<VirtualEventWebinar>
        {
            new() { DisplayName = "Azure Webinar" },
            new() { DisplayName = "Office 365 Workshop" }
        };

        var mockResponse = new Mock<IVirtualEventsWebinarsCollectionResponse>();
        mockResponse.Setup(r => r.Value).Returns(testWebinars);

        var mockWebinarsBuilder = new Mock<IVirtualEventsWebinarsCollectionRequestBuilder>();
        mockWebinarsBuilder.Setup(b => b.GetAsync(It.IsAny<CancellationToken>()))
                           .ReturnsAsync(mockResponse.Object);

        // 组装上层Mock
        var mockVirtualEventsBuilder = new Mock<IVirtualEventsRequestBuilder>();
        mockVirtualEventsBuilder.Setup(b => b.Webinars).Returns(mockWebinarsBuilder.Object);

        var mockSolutionsBuilder = new Mock<ISolutionsRequestBuilder>();
        mockSolutionsBuilder.Setup(b => b.VirtualEvents).Returns(mockVirtualEventsBuilder.Object);

        var mockGraphClient = new Mock<IGraphServiceClient>();
        mockGraphClient.Setup(c => c.Solutions).Returns(mockSolutionsBuilder.Object);

        var service = new WebinarService(mockGraphClient.Object);
        var result = await service.GetMany("AWS");

        Assert.Empty(result);
    }
}

关键说明

  1. 无需自定义接口:Microsoft Graph SDK提供了IGraphServiceClient、ISolutionsRequestBuilder、IVirtualEventsRequestBuilder、IVirtualEventsWebinarsCollectionRequestBuilder等一系列抽象接口,直接用于Mock即可。
  2. 分层Mock:从最底层的响应结果开始Mock,逐层向上构建依赖关系,最终得到可注入的IGraphServiceClient Mock实例。
  3. 覆盖全分支:测试用例覆盖了标题匹配、无匹配、响应为null、响应Value为null四种核心场景,确保业务逻辑的正确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 01:55:23