简体   繁体   English

C# 模拟单元测试 GraphServiceClient

[英]C# mock unit test GraphServiceClient

I have a problem writing my unit test in C# using Moq and xUnit.我在使用 Moq 和 xUnit 在 C# 中编写单元测试时遇到问题。

In my service I have the following code:在我的服务中,我有以下代码:

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();

But I don't know a method to mock the GraphClient function:但我不知道模拟GraphClient函数的方法:

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

Thank you Marcin Wojciechowski .谢谢Marcin Wojciechowski Posting your suggestion as an answer to help other community members.发布您的建议作为帮助其他社区成员的答案。

You can implement your own IHttpProvider and pass it to GraphServiceClient您可以实现自己的IHttpProvider并将其传递给GraphServiceClient

IHttpProvider mock 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);
        }
    }

Implement 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);
    }
}

You can refer to Unit Testing Graph API SDK c# , As a developer, I want to mock Graph responses to test my integration with the Microsoft Graph client SDK and Unit testing with Graph SDK您可以参考Unit Testing Graph API SDK c#作为开发人员,我想模拟 Graph 响应来测试我与 Microsoft Graph 客户端 SDK 的集成以及使用 Graph SDK 进行单元测试

Depending on your use case and existing code base you can also provide some empty stubs for both interfaces in the constructor call and use the ability to override the virtual functions.根据您的用例和现有代码库,您还可以在构造函数调用中为两个接口提供一些空存根,并使用覆盖虚函数的能力。 This comes in handy if you use some mock framework like Moq as provided within the 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);

By using this approach you don't have to hassle around with the concrete HTTP request done on the wire.通过使用这种方法,您不必为在线上完成的具体 HTTP 请求而烦恼。 Instead you simple override (nested) method calls with their parameters and define the returned object without a serialization / deserialization step.相反,您可以简单地覆盖(嵌套)方法调用及其参数,并在没有序列化/反序列化步骤的情况下定义返回的对象。 Also be aware, that within mock you can use eg It.IsAny<string>() and similar constructs to define if you need an exact parameter check or something else.还要注意,在模拟中,您可以使用例如It.IsAny<string>()和类似的构造来定义是否需要精确的参数检查或其他内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM