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

如何在单元测试中Mock GraphServiceClient并返回模拟响应?

解决GraphServiceClient单元测试Mock失败问题

问题场景

业务代码依赖GraphServiceClient获取域名注册商信息:

private GraphServiceClient gsc;

public RiskIQService(GraphServiceClient gsc)
{
    // 注意:原代码存在bug,未给私有字段赋值,需改为 this.gsc = gsc;
    gsc = gsc;
}

public async Task<string> getRegistrar(string domain)
{
    Microsoft.Graph.Models.Security.Hostname? response = (Microsoft.Graph.Models.Security.Hostname?) await gsc.Security.ThreatIntelligence.Hosts[domain].GetAsync();

    return response.Registrar;
}

尝试直接Mock GraphServiceClient时触发错误:

System.NotSupportedException: Unsupported expression: ... => ....GetAsync(null, CancellationToken.None) Non-overridable members (here: HostItemRequestBuilder.GetAsync) may not be used in setup / verification expressions.

原Mock代码:

private readonly Mock<GraphServiceClient> gscMock = new Mock<GraphServiceClient>();
var response = new Hostname(Registrar = "Registrar");
gscMock.Setup(x => x.Security.ThreatIntelligence.Hosts[It.IsAny<string>()].GetAsync(null, CancellationToken.None)).ReturnsAsync(response);

错误原因

Microsoft Graph SDK中的HostItemRequestBuilder.GetAsync是非虚方法,Moq仅支持Mock虚方法或接口定义的方法,直接对GraphServiceClient类进行链式Setup会触发非虚方法不支持的错误。

正确Mock方案

利用Graph SDK提供的各层级请求构建器接口,逐层Mock每个依赖节点:

// 1. Mock最底层的Host请求构建器,模拟GetAsync返回结果
var hostItemMock = new Mock<IHostItemRequestBuilder>();
var mockHostname = new Microsoft.Graph.Models.Security.Hostname { Registrar = "TestRegistrar" };
hostItemMock.Setup(x => x.GetAsync(It.IsAny<RequestConfiguration<DefaultQuerySettings>>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync(mockHostname);

// 2. Mock Hosts集合构建器,索引器返回上面的Host请求构建器
var hostsCollectionMock = new Mock<IHostsCollectionRequestBuilder>();
hostsCollectionMock.Setup(x => x[It.IsAny<string>()])
                   .Returns(hostItemMock.Object);

// 3. Mock ThreatIntelligence构建器,返回Hosts集合构建器
var threatIntelligenceMock = new Mock<IThreatIntelligenceRequestBuilder>();
threatIntelligenceMock.Setup(x => x.Hosts)
                      .Returns(hostsCollectionMock.Object);

// 4. Mock Security构建器,返回ThreatIntelligence构建器
var securityMock = new Mock<ISecurityRequestBuilder>();
securityMock.Setup(x => x.ThreatIntelligence)
            .Returns(threatIntelligenceMock.Object);

// 5. 最后Mock GraphServiceClient,返回Security构建器
var gscMock = new Mock<GraphServiceClient>();
gscMock.Setup(x => x.Security)
       .Returns(securityMock.Object);

// 注入Mock对象到业务服务
var riskIQService = new RiskIQService(gscMock.Object);
// 执行测试
var result = await riskIQService.getRegistrar("test-domain.com");
// 断言结果
Assert.Equal("TestRegistrar", result);

额外注意

  • 原业务代码的构造函数存在赋值错误,必须将gsc = gsc;改为this.gsc = gsc;,否则私有字段gsc始终为null,无法正常执行。
  • 若使用的Graph SDK版本不同,接口名称可能略有差异,请以实际SDK定义为准。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:15:26