C#模拟自定义界面

时间:2019-03-19 16:47:12

标签: c# asp.net-core moq xunit

我正在测试此函数,称为CreateMessageHistory,它具有2个依赖项,即IhttpClientFactory和另一个接口,我能够模拟httpclient,但无法模拟该接口

public class MessageHistoryService : IMessageHistoryService
{
    private const string API_MESSAGING_DB = "messages";
    private const string API_GET_MESSAGE_HISTORY_DESIGN = "_design/upn-timesent";
    private const string API_GET_MESSAGE_HISTORY_DESIGN_VIEW = "_view/upn-timesent-query";
    private readonly ICouchDbClients couchDbClient;
    private readonly IHttpClientFactory clientFactory;


    public MessageHistoryService(
        IHttpClientFactory clientFactory,
        ICouchDbClients couchDbClient)
    {
        this.couchDbClient = couchDbClient ??
            throw new ArgumentNullException(nameof(couchDbClient));

        this.clientFactory = clientFactory ??
            throw new ArgumentNullException(nameof(clientFactory));
    }

    public async Task CreateMessageHistory(Message message)
    {
        var client = this.clientFactory.CreateClient(NamedHttpClients.COUCHDB);

        var formatter = new JsonMediaTypeFormatter();
        formatter.SerializerSettings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented,
            NullValueHandling = NullValueHandling.Ignore,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };

        Guid id = Guid.NewGuid();

        var response = await this.couchDbClient.AuthenticatedQuery(async () => {
            return await client.PutAsync($"{API_MESSAGING_DB}/{id.ToString()}", message, formatter);
        }, NamedHttpClients.COUCHDB, client);

        if (!response.IsSuccessStatusCode)
        {
            throw new HttpRequestException(await response.Content.ReadAsStringAsync());
        }
    }
}

我似乎对此接口有疑问...

public interface ICouchDbClients
{
    Task<HttpResponseMessage> AuthenticatedQuery(Func<Task<HttpResponseMessage>> query, string name, HttpClient client);
}

这是该接口的实现:

public class CouchDbClients : ICouchDbClients
{
    private readonly Dictionary<string, string> authSessions;
    private readonly Dictionary<string, Credentials> couchDbCredentials;
    private readonly IOptions<Clients> clients;
    private readonly string AuthCouchDbCookieKeyName = "AuthSession";

    public CouchDbClients(IOptions<Clients> clients)
    {
        this.clients = clients ??
            throw new ArgumentNullException(nameof(couchDbCredentials));

        this.couchDbCredentials = new Dictionary<string, Credentials>();
        this.couchDbCredentials.Add(NamedHttpClients.COUCHDB, this.clients.Value.Work);

        this.authSessions = new Dictionary<string, string>();
    }

    public async Task<HttpResponseMessage> AuthenticatedQuery(Func<Task<HttpResponseMessage>> query, string name, HttpClient client)
    {
        int counter = 0;
        var response = new HttpResponseMessage();

        do
        {
            Authenticate(name, client);
            response = await query();

            if (response.IsSuccessStatusCode)
            {
                break;
            }
            else if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                this.authSessions[name] = GenerateCookie(client, name);
            }
            else
            {
                throw new HttpRequestException(await response.Content.ReadAsStringAsync());
            }

            counter++;
        } while (counter < 3);

        return response;
    }

    private void Authenticate(string name, HttpClient client)
    {
        CookieContainer container = new CookieContainer();
        var session = this.authSessions.ContainsKey(name);

        if (!session)
        {
            var newCookie = GenerateCookie(client, name);
            authSessions.Add(name, newCookie);
        }

        container.Add(
            client.BaseAddress,
            new Cookie(AuthCouchDbCookieKeyName, this.authSessions[name])
            );
    }

    private string GenerateCookie(HttpClient client, string name)
    {
        string authPayload = JsonConvert.SerializeObject(this.couchDbCredentials[name]);

        var authResult = client.PostAsync(
            "_session",
            new StringContent(authPayload, Encoding.UTF8, "application/json")
            ).Result;

        if (authResult.IsSuccessStatusCode)
        {
            var responseHeaders = authResult.Headers.ToList();
            string plainResponseLoad = authResult.Content.ReadAsStringAsync().Result;

            var authCookie = responseHeaders
                .Where(r => r.Key == "Set-Cookie")
                .Select(r => r.Value.ElementAt(0)).FirstOrDefault();

            if (authCookie != null)
            {
                int cookieValueStart = authCookie.IndexOf("=") + 1;
                int cookieValueEnd = authCookie.IndexOf(";");
                int cookieLength = cookieValueEnd - cookieValueStart;
                string authCookieValue = authCookie.Substring(cookieValueStart, cookieLength);
                return authCookieValue;
            }
            else
            {
                throw new Exception("There is auth cookie header in the response from the CouchDB API");
            }
        }
        else
        {
            throw new HttpRequestException(string.Concat("Authentication failure: ", authResult.ReasonPhrase));
        }
    }
}

这是我的单元测试:

[Fact]
    public async Task Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated()
        {
            var recipients = MockMessage.GetRecipients(279, 1, 2, 3);
            var message = MockMessage.GetMessage(recipients);

            mockStateFixture
                .MockMessageHistoryService
                .Setup(service => service.CreateMessageHistory(message));

            // ARRANGE
            var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);

            handlerMock
               .Protected()
               .Setup<Task<HttpResponseMessage>>(
                  "SendAsync",
                  ItExpr.IsAny<HttpRequestMessage>(),
                  ItExpr.IsAny<CancellationToken>())
               .ReturnsAsync(new HttpResponseMessage()
               {
                   StatusCode = HttpStatusCode.Created
               })
               .Verifiable();

            // create the mock client
            // use real http client with mocked handler here
            var httpClient = new HttpClient(handlerMock.Object)
            {
                BaseAddress = new Uri("http://10.179.236.207:5984/"),
            };

            mockStateFixture.MockIHttpClientFactory.Setup(x => x.CreateClient(NamedHttpClients.COUCHDB))
                                 .Returns(httpClient);

            //var httpResponseMessage = new Mock<Task<HttpResponseMessage>>();


            //httpResponseMessage.Setup


            var httpResponseMessage = new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.Created
            };


            //httpResponseMessage.Setup(x => x.StatusCode = HttpStatusCode.Created);

            //mockStateFixture.MockCouchDbClient.Setup(x => x.AuthenticatedQuery(
            //    async () =>
            //    {
            //        return await httpResponseMessage;
            //    },
            //    NamedHttpClients.COUCHDB,
            //    httpClient))
            //    .Returns(It.IsAny<Task<HttpResponseMessage>>);

            var messageHistoryService = new MessageHistoryService(
                mockStateFixture.MockIHttpClientFactory.Object, mockStateFixture.MockCouchDbClient.Object);

            var task = messageHistoryService.CreateMessageHistory(message);
            var type = task.GetType();
            Assert.True(type.GetGenericArguments()[0].Name == "VoidTaskResult");
            Assert.True(type.BaseType == typeof(Task));
            await task;
        }

我该如何模拟ICouchDbClient,我甚至必须这么做?

这是我得到的错误:

测试名称:

  

Data.Tests.MessageHistoryServiceTests + CreateMessageHistory.Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated   测试   全名:Data.Tests.MessageHistoryServiceTests + CreateMessageHistory.Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated   测试源:C:\ Data.Tests \ MessageHistoryServiceTests.cs:第36行   测试结果:测试持续时间失败:0:00:00.393

结果StackTrace:

  在Data.API.MessageHistoryService.CreateMessageHistory(Message   消息)在C:\ Data \ API \ MessageHistoryService.cs:第51行   Data.Tests.MessageHistoryServiceTests.CreateMessageHistory.Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated()   在C:\ Data.Tests \ MessageHistoryServiceTests.cs:line 100中   ---从引发异常的先前位置结束的堆栈跟踪---结果消息:System.NullReferenceException:Object   引用未设置为对象的实例。

0 个答案:

没有答案