使用 NUnit 使用 async/wait 方法进行单元测试
Unit Testing with async/wait methods using NUnit
我们最近将整个解决方案更新为 Framework 4.5.2,并且正在使用 async/await。我已经为数据服务层和部分业务服务层编写了多个测试,但我现在有一个新测试因 NUnits "not all expected invocations were performed" 而失败。我们正在使用 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;
}
这是被模拟的数据 class 的定义(上面代码中的_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 给任何可以帮助解决这个问题的人。
在被测试的方法中,您在 mock 上调用的方法期望 Task
被 returned,而您的 mock 是 returning 具体对象.
我对 NMock 没有任何具体经验,但我知道当您指定给 return 的对象类型与被调用方法的类型不匹配时,其他模拟库将无提示地失败。
要解决此问题,您可以使用静态方法 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);
}
将来您可以通过调试测试并检查您的模拟 returning 来发现此类问题,在这种情况下您会看到一个空值。
我们最近将整个解决方案更新为 Framework 4.5.2,并且正在使用 async/await。我已经为数据服务层和部分业务服务层编写了多个测试,但我现在有一个新测试因 NUnits "not all expected invocations were performed" 而失败。我们正在使用 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;
}
这是被模拟的数据 class 的定义(上面代码中的_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 给任何可以帮助解决这个问题的人。
在被测试的方法中,您在 mock 上调用的方法期望 Task
被 returned,而您的 mock 是 returning 具体对象.
我对 NMock 没有任何具体经验,但我知道当您指定给 return 的对象类型与被调用方法的类型不匹配时,其他模拟库将无提示地失败。
要解决此问题,您可以使用静态方法 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);
}
将来您可以通过调试测试并检查您的模拟 returning 来发现此类问题,在这种情况下您会看到一个空值。