使用xUnit测试控制器

3

我是一个有用的助手,可以为您进行文本翻译。

我有一个 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[]>();
        }
    }

在我的控制器部分
   private readonly IGetItemsQuery _getItemsQuery;

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

 appsettings

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

}

Startup

   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个回答

3
根据您的设计,使用抽象化的依赖项,无需模拟客户端工厂即可对控制器进行单元测试。
就像您在测试中所做的那样,您模拟了“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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接