单元测试异步任务时出错<ihttpactionresult>

时间:2016-06-06 08:52:06

标签: c# unit-testing mocking tdd asp.net-web-api2

我的一个控制器中有以下方法: -

//GET: api/Books/5
[ResponseType(typeof(BookDetailDTO))]
public async Task<IHttpActionResult> GetBook(int id)
{
    var includeProperties = "Author,Genre";
    var item = _bookRepository.GetBookById(id, includeProperties);
    //var item = await Task.Run(() => _bookRepository.GetBookById(id, includeProperties));
}

我试图针对它创建一个单元测试: -

[Test]
public async Task GetBook_Should_Get_A_Single_Book_By_Its_ID()
{
    // Arrange
    _booksRepositoryMock.Setup(x => x.GetBooks("Author")).Returns(books.AsQueryable());

    // Act
    var result = await objController.GetBook(1) as OkNegotiatedContentResult<Book>;

    // Assert
    Assert.IsNotNull(result);
    Assert.AreEqual(books[1].Title, result.Content.Title);
}

问题在于以下一行: -

var item = _bookRepository.GetBookById(id, includeProperties);

item始终为空,因为现在模拟的_bookRepository未被命中。但是,在运行实际应用程序时,它工作正常,我通过ID得到了该书。

如何调整测试/代码并使其成功运行?

感谢您的帮助和时间

1 个答案:

答案 0 :(得分:0)

我看待它的方式你没有测试正确的东西。

您正在测试的是您的数据库层,因此您可以取消所有异步内容。

单元测试是关于一个非常精细的级别并测试一个简单的事情,而不是一个命中数据库的api异步调用。这是一个集成测试,而不是单元测试。

因此,请针对您的数据库层编写测试方法,并将其保留。如果db层正常运行,你的api将返回正确的东西。

更新

这是我要做的。

为您的数据库层编写单元测试。保留当前的模拟代码,设置模拟书对象并检查在触发GetBookByID方法时是否获得它。那是在图书回购级别,所以你正在测试你是否正确。它可能是发生此测试的BookRepoTest类。

现在,我会在你的repo和你的控制器之间添加一个额外的层。获取数据的一般方法,想象一个看起来像这样的层:

public DataAccess class
{
    IRepo _repo;
    public DataAccess( IRepo repo){
         _repo = repo;
    }

    public GetRepo(){
        return _repo;
    }
}

当然会有更多的代码,但想法是注入依赖。现在你可以模拟这种依赖,而不用触及你的实际回购。然后你继续检查你的控制器,当输入模型错误时,当id不存在等时会发生什么。

现在您已将代码分开并使其更易于测试。在构建项目时,我总是这样做。当你在你的控制器中看到像UnitOfWork这样的东西的时候,已经有一种气味,你没有足够的关注点分离。 根据您当前的代码,一旦调用UnitOfWork方法,实际上是否使用了这个模拟的repo,它甚至都不清楚。

您甚至可以将repo依赖项(基于接口)添加到控制器本身的构造函数中。然后你也可以注入这种方式。无论哪种方法更容易适用于您。