【问题标题】:Unit Testing with async/wait methods using NUnit使用 NUnit 使用异步/等待方法进行单元测试
【发布时间】:2016-02-16 18:02:45
【问题描述】:

我们最近将整个解决方案更新到了 Framework 4.5.2,并且正在使用 async/await。我已经为数据服务层和部分业务服务层编写了几个测试,但是我现在有一个新的测试失败,因为 NUnits 的“并非所有预期的调用都已执行”。我们正在使用 NUnit V3.0.1 和 NMock 2.0.0。

这是正在测试的方法:

public async Task<objQuote> RetrieveQuoteAsync(int quoteid)
    {
        var q = await _data.RetrieveQuoteAsync(quoteid);
        if (q != null)
        {
            q.Milestones = await _data.RetrieveAllMilestonesForQuoteAsync(quoteid);
            q.Assignments = await _data.RetrieveAssignmentsForQuoteAsync(quoteid);
        }
        return q;
    }

这是被模拟的数据类的定义(上面代码中的_data):

public interface IQuotesData
{
    string ConnectionString { get; set; }


    Task<int> SaveQuoteAsync(objQuote quote);

    Task<objQuote> RetrieveQuoteAsync(int quoteid);

    //objQuote RetrieveQuoteWithoutAssignments(int quoteid);

    Task<List<objQuote>> RetrieveAllQuotesAsync();

    Task<List<objQuote>> RetrieveAllQuotesForFYAsync(int fy);

    Task<int> SaveQuoteActivityAsync(objQuoteActivity qa);

    Task DeleteQuoteAsync(int quoteid);

    Task<int> SaveQuoteMilestoneAsync(objQuoteMilestone ms);

    Task<List<objQuoteMilestone>> RetrieveAllMilestonesForQuoteAsync(int quoteid);

    Task<List<objQuoteActivity>> RetrieveAllQuoteActivitiesAsync(int quoteid);

    Task<int> SaveAssignmentAsync(objAssignment ass);

    Task<int> SaveAssignmentOverheadAsync(objFAOverHead oh);

    Task<List<objFAOverHead>> RetrieveAllOverheadsForAssignment(int assignmentid);

    Task<objAssignment> RetrieveAssignmentAsync(int assid);

    Task<List<objAssignment>> RetrieveAssignmentsForQuoteAsync(int quoteid);

    Task<int> SaveDelegationAsync(objDelegation del);

    Task<int> SaveDelegationOverheadAsync(objFAOverHead oh);

    Task<List<objFAOverHead>> RetrieveAllOverheadsForDelegation(int delegationid);

    Task<List<objDelegation>> RetrieveDelegationsforAssignment(int assid);

    Task<int> SaveCommentAsync(objQuoteComment comment);

    Task<List<objQuoteComment>> RetrieveAllCommentsForQuoteAsync(int quoteid);
}

这是我的测试:

 [Test]
    public async void Can_Retrieve_Quote()
    {
        const int quoteid = 42;
        var quote = new objQuote() { ID = 42};
        var msList = new List<objQuoteMilestone>();
        var assignmentList = new List<objAssignment>();

        Expect.Once.On(_data).Method("RetrieveQuoteAsync").With(Is.EqualTo(quoteid)).Will(Return.Value(quote));
        Expect.Once.On(_data).Method("RetrieveAllMilestonesForQuoteAsync").With(Is.EqualTo(quoteid)).Will(Return.Value(msList));
        Expect.Once.On(_data).Method("RetrieveAssignmentsForQuoteAsync").With(Is.EqualTo(quoteid)).Will(Return.Value(assignmentList));

        var biz = new QuotesBiz(_data, _empData, _logger, _mailer);
        Assert.IsNotNull(biz);
        var results = await biz.RetrieveQuoteAsync(quoteid);
        Assert.That(results != null);

    }

此时我不确定这是编码问题还是测试问题。被测代码的“if”语句中的两个调用似乎没有被执行。

TIA 给任何可以帮助解决这个问题的人。

【问题讨论】:

  • 我对 nmock 一无所知,但我会尝试 .Will(Return.Value(Task.FromResult(quote)));(即将异步返回值包装在 Task.FromResult 中)
  • 这就是解决方案。现在测试通过了。

标签: c# unit-testing asynchronous nunit


【解决方案1】:

从正在测试的方法中,您在模拟上调用的方法期望在模拟返回具体对象的地方返回 Task。

我没有任何专门使用 NMock 的经验,但我知道当您指定返回的对象的类型与被调用的方法的类型不匹配时,其他模拟库会静默失败。

要解决这个问题,您可以像这样使用静态方法Task.FromResult:

[Test]
public async void Can_Retrieve_Quote()
{
    const int quoteid = 42;
    var quote = new objQuote() { ID = 42};
    var msList = new List<objQuoteMilestone>();
    var assignmentList = new List<objAssignment>();

    Expect.Once.On(_data).Method("RetrieveQuoteAsync").With(Is.EqualTo(quoteid)).Will(Return.Value(Task.FromResult(quote)));
    Expect.Once.On(_data).Method("RetrieveAllMilestonesForQuoteAsync").With(Is.EqualTo(quoteid)).Will(Return.Value(Task.FromResult(msList)));
    Expect.Once.On(_data).Method("RetrieveAssignmentsForQuoteAsync").With(Is.EqualTo(quoteid)).Will(Return.Value(Task.FromResult(assignmentList)));

    var biz = new QuotesBiz(_data, _empData, _logger, _mailer);
    Assert.IsNotNull(biz);
    var results = await biz.RetrieveQuoteAsync(quoteid);
    Assert.That(results != null);

}

将来您可以通过调试测试并检查您的模拟返回的内容来发现此类问题,在这种情况下您会看到一个空值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 2014-07-20
    • 1970-01-01
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多