当使用await调用方法时,模拟设置返回null

时间:2017-11-14 15:32:42

标签: c# asp.net-mvc unit-testing mocking moq

我正在尝试在MVC控制器中对一个动作进行单元测试,但是模拟对象返回null。

我有一个ClientProxy接口

public interface IClientProxy
{
    Task<T> Get<T>(string uri);
}

通过以下具体实施

public async Task<T> Get<T>(string uri)
{
    using (HttpClient httpClient = new HttpClient())
    {
        ConfigureClient(httpClient);
        var response = await httpClient.GetAsync(uri);
        response.EnsureSuccessStatusCode();
        return await Task.Run(() => GetResultFromResponse<T>(response));
    }
}

这是我的行动

public async Task<ActionResult> Index()
{
    var categories = await _proxy.Get<PagedResults<Category>>("/category/get");
    return View("index", null, JsonConvert.SerializeObject(categories));
}

这是单元测试类

public class CategoryControllerTests
{
    private readonly CategoryController _controller;
    private readonly Mock<IClientProxy> _mockProxy;

    public CategoryControllerTests()
    {
        _mockProxy = new Mock<IClientProxy>();
        _controller = new CategoryController(_mockProxy.Object);
    }

    [Fact]
    public async Task IndexPageRenders()
    {
        // Arrange
        var fakeResult = new PagedResults<Category>
        {
            Paging = new Paging
            {
                Page = 1, 
                PageSize = 10,
                TotalRecords = 2
            },
            Results = new List<Category>
            {
                new Category { CategoryId = 1, Name = "Category One" },
                new Category { CategoryId = 2, Name = "Category Two" }
            }
        };

        var result = JsonConvert.SerializeObject(fakeResult);

        _mockProxy.Setup(p => p.Get<PagedResults<Category>>(It.IsAny<string>())).ReturnsAsync(fakeResult);

        // Act
        var action = await _controller.Index() as ViewResult;

        // Assert
        _mockProxy.Verify(p => p.Get<PagedResults<Category>>(It.IsAny<string>()), Times.Exactly(1));
    }
}

目前,get方法的模拟对象设置未被命中,类别为nu​​ll(验证失败,暗示从未调用模拟方法)。但是,如果从操作中删除await关键字,则返回类别。我宁愿不删除等待只是为了通过测试因为它在那里有充分的理由,所以任何帮助将不胜感激。

提前致谢。

1 个答案:

答案 0 :(得分:0)

  

目前,get方法的模拟对象设置未被命中,类别为nu​​ll(验证失败,暗示从未调用模拟方法)。

这意味着模拟对象没有作为依赖项传递给正在测试的控制器,因此在执行测试时不会被调用。

这是一个Minimal, Complete, and Verifiable example,演示了如何在这种情况下设置和执行测试。

使用以下

public class MyModel {
    public int MyIntProperty { get; set; }
    public string MyStringProperty { get; set; }
}

public interface IClientProxy {
    Task<T> Get<T>(string uri);
}

public class MyController : Controller {
    IClientProxy _proxy;

    public MyController(IClientProxy _proxy) {
        this._proxy = _proxy;
    }

    public async Task<ActionResult> Index() {
        var categories = await _proxy.Get<MyModel>("/category/get");
        return View(categories);
    }
}

以下测试与MSTest,Moq和Fluent Assertions一起使用,其中流程完成并通过。

[TestClass]
public class MyController_Should {
    [TestMethod]
    public async Task _Render_Index_Page() {
        // Arrange
        var fakeResult = new MyModel {
            MyIntProperty = 0,
            MyStringProperty = "Hello World."
        };

        var _mockProxy = new Mock<IClientProxy>();
        _mockProxy
            .Setup(_ => _.Get<MyModel>(It.IsAny<string>()))
            .ReturnsAsync(fakeResult);

        var _controller = new MyController(_mockProxy.Object);

        // Act
        var action = await _controller.Index() as ViewResult;

        // Assert
        _mockProxy.Verify(_ => _.Get<MyModel>(It.IsAny<string>()), Times.Exactly(1));

        action.Should().NotBeNull();

        var model = action.Model;
        model.Should().NotBeNull()
            .And.BeOfType<MyModel>()
            .And.Be(fakeResult);
    }
}

我建议您查看此示例,然后将其与您设计测试的方式进行比较,看看是否可以确定可能导致问题的原因。