Тестирование контроллера с помощью xUnit - PullRequest
0 голосов
/ 28 января 2019

У меня есть webapi, где он должен вызвать другую конечную точку и получить данные.

Мой текущий код выглядит следующим образом

// реализация клиента http

public interface IHttpClientFactory
{
    HttpClient Create();
}

public class HttpClientFactory : IHttpClientFactory
{
    private readonly ApplicationSettings _applicationSettings;
    HttpClient _httpClient;

    public HttpClientFactory(IOptions<ApplicationSettings> settings)
    {
        _applicationSettings = settings.Value;
    }
    public HttpClient Create()
    {
        if (_httpClient != null)
            return _httpClient;

        var client = new HttpClient()
        {
            BaseAddress = new Uri($"{_applicationSettings.BaseUrl}")
        };
        _httpClient = client;
        return _httpClient;
    }
}

 public interface IGetItemsQuery
{
    Task<IEnumerable<T>> Execute<T>(string url);
}

public class GetItemQuery: IGetItemsQuery
{
    private readonly IHttpClientFactory _httpClientFactory;
    public GetPhotosQuery(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public async Task<IEnumerable<T>> Execute<T>(string url)
    {
        using (var response = await _httpClientFactory.Create().GetAsync($"{url}").ConfigureAwait(false))
        {
            response.EnsureSuccessStatusCode();
            var resp = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            var items = JArray.Parse(resp);
            return items.ToObject<T[]>();
        }
    }

Inчасть моего контроллера

   private readonly IGetItemsQuery _getItemsQuery;

       public HomeController(IGetItemsQuery getItemsQuery)
    {
        _getItemsQuery = getItemsQuery;
    }

 appsettings

     "ApplicationSettings": {
      "BaseUrl": "http://someendpoint.com/"

}

Запуск

   services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
        services.AddScoped<IGetItemsQuery, GetPhotosQuery>();
        services.AddScoped<IHttpClientFactory, HttpClientFactory>();

Я хочу попробовать что-то подобное в моем тесте

     [Fact]
    public void Test_Index()
    {
        // Arrange
        var itemsQuery = new Mock<IGetItemsQuery>();
        var controller = new HomeController(itemsQuery.Object);

        // Act
        var result = controller.Index();

        // Assert
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.Null(viewResult.ViewName);
    }

Этосоздание фиктивного IGetItemsQuery, но это не издевается над фактическим IHttpClientFactory.

Есть ли способ сделать это

1 Ответ

0 голосов
/ 28 января 2019

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

Как вы сделали в своем тесте, вы имитируете IGetItemsQuery, но не настроили его на поведение, ожидаемое при вызове в тесте.

Если, например, контроллертестируемый метод выглядит примерно так

private readonly IGetItemsQuery getItemsQuery;

public HomeController(IGetItemsQuery getItemsQuery) {
    this.getItemsQuery = getItemsQuery;
}

public async Task<IActionResult> Index() {
    var url = "....";

    var items = await getItemsQuery.Execute<MyItem>(url);

    return View(items);
}

Тогда изолированный модульный тест для действия Index в качестве тестируемого метода может выглядеть примерно так:

[Fact]
public async Task Index_Should_Return_View_With_Items() {
    // Arrange
    var itemsQuery = new Mock<IGetItemsQuery>();

    var items = new MyItem[] {
        new MyItem(),
        new MyItem()
    };

    itemsQuery.Setup(_ => _.Execute<MyItem>(It.IsAny<string>()))
        .ReturnsAsync(items);

    var controller = new HomeController(itemsQuery.Object);

    // Act
    var result = await controller.Index();

    // Assert        
    var viewResult = Assert.IsType<ViewResult>(result);
    Assert.Null(viewResult.ViewName);
}
...