Func <HttpRequestMessage>Вопросы, связанные с издевательствами для модульных тестов - PullRequest
0 голосов
/ 24 мая 2019

Я использую Moq в своем тесте XUnit.В методах зависимости он содержит параметр Func<HttpResponseMessage>.Вот модульный тест, который я написал:

      [Fact]
    public async Task Test()
    {
        //Arrange
        var content = new StringContent(TestData.GetResponse().ToString(), Encoding.UTF8, "application/json");
        var httpResponse = new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.OK,
            Content = content
        };
        _mockRetryHttpRequest.Setup(x => x.ExecuteAsync(It.IsAny<Func<HttpRequestMessage>>(), It.IsAny<HttpClient>(), It.IsAny<int>()))
                           .ReturnsAsync(httpResponse);
        var libraryService = new LibraryService(_mockRetryHttpRequest.Object);

        //Act
        var response = await libraryService.GetResponseForSearch(new SearchRequest(), null);

        //Assert
        response.Should().NotBeNull();
    }

А вот фактический метод, который мне нужно проверить на

public class LibraryService : ILibraryService
{
    private IRetryHttpRequest _retryHttpRequest;
    public LibraryService(IRetryHttpRequest retryHttpRequest)
    {
        _retryHttpRequest = retryHttpRequest;
    }


    public async Task<ResponseModel> GetResponseForSearch(SearchRequest searchRequest, HttpClient client)
    {
        //send request and retry if failed
        ResponseModel result = new ResponseModel();
        HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);

        //process response
        if (httpResponseMessage != null)
        {
            string response = await httpResponseMessage.Content.ReadAsStringAsync();
            result = JsonConvert.DeserializeObject<ResponseModel>(response);
        }
        return result;
    }
}

public class RetryHttpRequest : IRetryHttpRequest
{
    public async Task<HttpResponseMessage> ExecuteAsync(Func<HttpRequestMessage> requestMessage, HttpClient client, int maxTryValue)
    {
        var content = new StringContent("From Execute Async", Encoding.UTF8, "application/json");
        var httpResponse = new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.OK,
            Content = content
        };
        return httpResponse;
    }
}

Когда я прошел код, для этой строки кода нижепеременная httpResponseMessage возвращает null, несмотря на то, что я уже высмеял ее с ответом 200 в модульном тесте.

HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);

Ответы [ 2 ]

1 голос
/ 04 июня 2019

У вас не должно быть асинхронного метода тестирования.Сделайте это синхронно, а затем вместо ожидания сделайте следующее:

var task = lgService.GetResponseForSearch(new SearchRequest(), null);

task.Wait();

var response = task.Result;

response.Should().NotBeNull();
1 голос
/ 29 мая 2019

Хотя вопрос, по-видимому, не имеет полного объяснения, приведенное ниже описание используется в демонстрационных целях, чтобы показать, как протестировать целевой метод с помощью moq.

Предполагая следующее

public interface IRetryHttpRequest {
    Task<HttpResponseMessage> ExecuteAsync(Func<HttpRequestMessage> requestMessage, HttpClient client, int maxTryValue);
}

public class LibraryService : ILibraryService {
    private IRetryHttpRequest _retryHttpRequest;
    public LibraryService(IRetryHttpRequest retryHttpRequest) {
        _retryHttpRequest = retryHttpRequest;
    }

    public async Task<ResponseModel> GetResponseForSearch(SearchRequest searchRequest, HttpClient client) {
        //send request and retry if failed
        ResponseModel result = new ResponseModel();
        HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);

        //process response
        if (httpResponseMessage != null) {
            string response = await httpResponseMessage.Content.ReadAsStringAsync();
            result = JsonConvert.DeserializeObject<ResponseModel>(response);
        }
        return result;
    }
}

public interface ILibraryService {

}

Обратите внимание на синтаксические изменения, которые привели бы к ошибкам с исходным кодом, показанным в вопросе.

Следующий тест демонстрирует, как протестировать метод LibraryService.GetResponse и подтвердить ожидаемое поведение

public async Task SampleTest() {
    //Arrange
    var content = new StringContent("{}", Encoding.UTF8, "application/json");
    var httpResponse = new HttpResponseMessage() {
        StatusCode = HttpStatusCode.OK,
        Content = content
    };

    var _mockRetryHttpRequest = new Mock<IRetryHttpRequest>();
    _mockRetryHttpRequest
        .Setup(_ => _.ExecuteAsync(It.IsAny<Func<HttpRequestMessage>>(), It.IsAny<HttpClient>(), It.IsAny<int>()))
        .ReturnsAsync(httpResponse);

    var lgService = new LibraryService(_mockRetryHttpRequest.Object);

    //Act
    var response = await lgService.GetResponseForSearch(new SearchRequest(), null);

    //Assert
    response.Should().NotBeNull();
}

FluentAssertions использовался для подтверждения ожидаемого поведения.

Некоторые моменты, на которые следует обратить внимание

  • Испытуемому субъекту были предоставлены только те зависимости, которые фактически необходимы для выполнения теста до его завершения. Что означает, что HttpClient на самом деле не нужно для макета

  • Для получения ответа на утверждение необходимо также ожидать тестируемого метода.

  • Поскольку у меня нет доступа к вашим тестовым данным, я использовал пустой объект JSON "{}" для представления содержимого ответа, чтобы позволить JsonConvert работать

  • Тогда я бы посоветовал вам просмотреть данные тестов, которые десериализованы. Это может быть причиной отказа, поскольку это единственное место, где result может быть установлено на null, поскольку оно инициализируется в верхней части функции.

...