简体   繁体   English

使用NUnit使用异步/等待方法进行单元测试

[英]Unit Testing with async/wait methods using NUnit

We recently updated our entire solution to Framework 4.5.2 and are using async/await. 我们最近更新了Framework 4.5.2的整个解决方案,并使用async / await。 I have written several tests already for the data services layer and part of the business services layer, but I now have a new test that fails with NUnits' "not all expected invocations were performed". 我已经为数据服务层和业务服务层的一部分编写了几个测试,但我现在有一个新的测试失败,NUnits“并非所有预期的调用都被执行”。 We are using NUnit V3.0.1 and NMock 2.0.0. 我们使用的是NUnit V3.0.1和NMock 2.0.0。

This is the method under test: 这是测试中的方法:

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;
    }

And this is the definition for the data class being mocked (_data in the above code): 这是被模拟的数据类的定义(上面代码中的_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);
}

And this is my Test: 这是我的测试:

 [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);

    }

At this point I'm not sure if it's a coding problem or a testing problem. 此时我不确定这是编码问题还是测试问题。 It appears that the two calls inside the "if" statement of the code under test are not being executed. 看来,正在测试的代码的“if”语句中的两个调用没有被执行。

TIA to anyone that can help figure this out. TIA对任何可以帮助解决这个问题的人都有帮助。

From within the method being tested the methods that you are calling on the mock are expecting a Task to be returned where your mock is returning the concrete object instead. 从正在测试的方法中,您在模拟上调用的方法期望返回一个Task ,而mock返回具体对象。

I don't have any experience with NMock specifically but I know other mocking libraries will fail silently when the type of the object you specify to return does not match that of the method being called. 我没有具体的NMock经验,但我知道当你指定返回的对象的类型与被调用的方法的类型不匹配时,其他模拟库将无声地失败。

To solve this you can use the static method Task.FromResult like so: 要解决这个问题,您可以使用静态方法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);

}

In the future you can catch issues like these by debugging the test an inspecting what your mocks are returning, in this case you would see a null. 在将来,你可以通过调试测试来检查你的模拟返回的内容来捕获这些问题,在这种情况下你会看到null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM