【问题标题】:C# mock unit test GraphServiceClientC#模拟单元测试GraphServiceClient
【发布时间】:2021-12-08 01:56:37
【问题描述】:

我在 C# 中使用 Moq 和 xUnit 编写单元测试时遇到问题。

在我的服务中,我有以下代码:

var options = new TokenCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};

var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential);


return (await graphClient.Users.Request().Filter($"displayName eq '{mobilePhone}'").GetAsync()).FirstOrDefault();

但我不知道模拟GraphClient 函数的方法:

graphClient.Users.Request().Filter($"displayName eq '{mobilePhone}'").GetAsync()).FirstOrDefault();

【问题讨论】:

  • 您能否详细说明您尝试了什么以及失败的地方?另外,请参考How to Ask
  • 这能回答你的问题吗? How to mock Microsoft Graph API SDK Client?
  • @rickvdbosch 我的问题是我不知道如何在我的单元测试中模拟 GraphServiceClient ?我必须在其中为我的方法“foo()”编写一个单元测试,使用 GraphServiceClient,但我不知道如何模拟响应。

标签: c# azure moq xunit


【解决方案1】:

根据您的用例和现有代码库,您还可以在构造函数调用中为这两个接口提供一些空存根,并使用覆盖虚拟函数的能力。如果您使用 documentation 中提供的 Moq 等模拟框架,这会派上用场:

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

ManagedDevice md = new ManagedDevice
{
    Id = "1",
    DeviceCategory = new DeviceCategory()
    {
        Description = "Sample Description"
    }
};

// setup the calls
mockGraphClient.Setup(g => g.DeviceManagement.ManagedDevices["1"].Request().GetAsync(CancellationToken.None)).ReturnsAsync(md).Verifiable();

// Act
var graphClient = mockGraphClient.Object;
var device = await graphClient.DeviceManagement.ManagedDevices["1"].Request().GetAsync(CancellationToken.None);

// Assert
Assert.Equal("1",device.Id);

通过使用这种方法,您不必费心处理在网络上完成的具体 HTTP 请求。相反,您只需使用参数覆盖(嵌套)方法调用,并在没有序列化/反序列化步骤的情况下定义返回的对象。另请注意,在模拟中您可以使用例如It.IsAny&lt;string&gt;() 和类似的构造来定义您是否需要精确的参数检查或其他东西。

【讨论】:

    【解决方案2】:

    谢谢Marcin Wojciechowski。发布您的建议作为帮助其他社区成员的答案。

    您可以实现自己的IHttpProvider 并将其传递给GraphServiceClient

    IHttpProvider 模拟

    public class MockRequestExecutingEventArgs
        {
            public HttpRequestMessage RequestMessage { get; }
            public object Result { get; set; }
     
            public MockRequestExecutingEventArgs(HttpRequestMessage message)
            {
                RequestMessage = message;
            }
        }
        public class MockHttpProvider : IHttpProvider
        {
            public ISerializer Serializer { get; } = new Serializer();
     
            public TimeSpan OverallTimeout { get; set; } = TimeSpan.FromSeconds(10);
            public Dictionary<string, object> Responses { get; set; } = new Dictionary<string, object>();
            public event EventHandler<MockRequestExecutingEventArgs> OnRequestExecuting;
            public void Dispose()
            {
            }
     
            public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
            {
                return Task.Run(() =>
                {
                    string key = "GET:" + request.RequestUri.ToString();
                    HttpResponseMessage response = new HttpResponseMessage();
                    if(OnRequestExecuting!= null)
                    {
                        MockRequestExecutingEventArgs args = new MockRequestExecutingEventArgs(request);
                        OnRequestExecuting.Invoke(this, args);
                        if(args.Result != null)
                        {
                            response.Content = new StringContent(Serializer.SerializeObject(args.Result));
                        }
                    }
                    if (Responses.ContainsKey(key) && response.Content == null)
                    {
                        response.Content = new StringContent(Serializer.SerializeObject(Responses[key]));
                    }
                    return response;
                });
            }
     
            public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
            {
                return SendAsync(request);
            }
        }
    

    实现TestClass

    [TestClass]
    public class MeEndpointTests
    {
        [TestMethod]
        public void MeEndpoint_GetMeInfo()
        {
            string requestUrl = "https://graph.microsoft.com/v1.0/me";
            MockHttpProvider mockHttpProvider = new MockHttpProvider();
            mockHttpProvider.Responses.Add("GET:" + requestUrl, new User()
            {
                DisplayName = "Test User"
            });
            GraphServiceClient client = new GraphServiceClient(new MockAuthenticationHelper(), mockHttpProvider);
            User response = client.Me.Request().GetAsync().Result;
     
            Assert.AreEqual("Test User", response.DisplayName);
        }
        [TestMethod]
        public void MeEndpoint_GetMeInfo_OnRequestExecuting()
        {
            string requestUrl = "https://graph.microsoft.com/v1.0/me";
            MockHttpProvider mockHttpProvider = new MockHttpProvider();
            mockHttpProvider.OnRequestExecuting += delegate (object sender, MockRequestExecutingEventArgs eventArgs)
            {
                if(eventArgs.RequestMessage.RequestUri.ToString() == requestUrl)
                {
                    eventArgs.Result = new User()
                    {
                        DisplayName = "Test User"
                    };
                }
            };
            GraphServiceClient client = new GraphServiceClient(new MockAuthenticationHelper(), mockHttpProvider);
            User response = client.Me.Request().GetAsync().Result;
     
            Assert.AreEqual("Test User", response.DisplayName);
        }
    }
    

    您可以参考Unit Testing Graph API SDK c#As a developer, I want to mock Graph responses to test my integration with the Microsoft Graph client SDKUnit testing with Graph SDK

    【讨论】:

      猜你喜欢
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-27
      • 2011-09-15
      相关资源
      最近更新 更多