У меня есть эта функция, которую я тестирую, которая называется 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;
}
Как мне издеваться над ICouchDbClients, мне вообще нужно?
Это ошибка, которую я получаю:
Имя теста:
Data.Tests.MessageHistoryServiceTests + CreateMessageHistory.Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated Тест FULLNAME: Data.Tests.MessageHistoryServiceTests + CreateMessageHistory.Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated Test Источник: C: \ Data.Tests \ MessageHistoryServiceTests.cs: линия 36 Тест Результат: Failed Test Продолжительность: 0: 00: 00,393
Результат StackTrace:
в Data.API.MessageHistoryService.CreateMessageHistory (сообщение с сообщением) в C: \ Data \ API \ MessageHistoryService.cs: строка 51 в Data.Tests.MessageHistoryServiceTests.CreateMessageHistory.Should_NotThrowHttpist_Service.SignSignSignSignSignSignSigner.West.Web.Service.West.Web.West.Web.Service.Web.West.Windowscs: строка 100 --- Конец трассировки стека из предыдущего местоположения, где было сгенерировано исключение --- Сообщение о результате: System.NullReferenceException: ссылка на объект не установлена на экземпляр объекта.