C# NSubstitute Async返回null,尽管定义了返回对象
我有一个单元测试,它应该返回指定的对象,但它返回null 要测试的数据提供程序:C# NSubstitute Async返回null,尽管定义了返回对象,c#,unit-testing,asynchronous,C#,Unit Testing,Asynchronous,我有一个单元测试,它应该返回指定的对象,但它返回null 要测试的数据提供程序: public class PlanDataProvider : BaseDomainServiceProvider, IPlanDataProvider { //CTOR public PlanDataProvider(IDataAccessTemplate template, IEntityStore entityStore) : base(template, entityStore) {
public class PlanDataProvider : BaseDomainServiceProvider, IPlanDataProvider
{
//CTOR
public PlanDataProvider(IDataAccessTemplate template, IEntityStore entityStore) : base(template, entityStore)
{
}
public async Task<DefaultActionPlan> GetDefaultActionPlan(string referenceListId)
{
var objectId = GetObjectId(referenceListId);
var defaultActionPlan = await Template.InvokeAsync(context => Task.FromResult(EntityStore.GetEntityById<DefaultActionPlan, ObjectId>
(
context.ActivityContext as IDataAccessContext,
typeof(DefaultActionPlan).FullName,
objectId
)));
}
}
公共类PlanDataProvider:BaseDomainServiceProvider、IPlanDataProvider
{
//执行器
public PlanDataProvider(IDataAccessTemplate模板,entityStore entityStore):基本(模板,entityStore)
{
}
公共异步任务GetDefaultActionPlan(字符串referenceListId)
{
var objectId=GetObjectId(referenceListId);
var defaultActionPlan=wait Template.InvokeAsync(上下文=>Task.FromResult(EntityStore.GetEntityById
(
context.ActivityContext作为IDataAccessContext,
typeof(DefaultActionPlan).FullName,
目标
)));
}
}
测试:
public async Task GetPlan_BadPlanID()
{
//Arrange
string badPlanId = "57509afbc6b48d3f33b2dfcd";
...snip...
DefaultActionPlan jj = new ObjectId(badPlanId);
//create EntityStore object
var dataxs = Substitute.For<IDataAccessContext>();
var estore = Substitute.For<IEntityStore>();
estore.GetEntityById<DefaultActionPlan, ObjectId>(
dataxs,
typeof(DefaultActionPlan).FullName,
new ObjectId(badPlanId))
.Returns(Task.FromResult(jj).Result);
var dataAccessTemplate = Substitute.For<IDataAccessTemplate>();
PlanDataProvider pdp = new PlanDataProvider(dataAccessTemplate, estore);
//Act
var t = await pdp.GetDefaultActionPlan(badPlanId);
//Now this confuses me as the compiler thinks t is DefaultActionPlan NOT Task<DefaultActionPlan>???
}
public异步任务GetPlan\u BadPlanID()
{
//安排
字符串badPlanId=“57509afbc6b48d3f33b2dfcd”;
剪
DefaultActionPlan jj=新对象ID(badPlanId);
//创建EntityStore对象
var dataxs=Substitute.For();
var estore=替换为();
estore.GetEntityById(
dataxs,
typeof(DefaultActionPlan).FullName,
新对象ID(badPlanId))
.Returns(Task.FromResult(jj.Result));
var dataAccessTemplate=Substitute.For();
PlanDataProvider pdp=新的PlanDataProvider(dataAccessTemplate,estore);
//表演
var t=等待pdp.GetDefaultActionPlan(badPlanId);
//现在这让我很困惑,因为编译器认为t是DefaultActionPlan而不是Task???
}
反正t在任何时候都返回null eferytime,调试测试t为null,因为GetDefaultActionPlan没有返回jj,而是返回null
我错过了什么让jj回来
编辑: Eris和Gabe都正确地指出,我对IEntityStore的模拟不足以作为该值……即使它指定了返回,也不会传递给包装的InvokeAsync,因此我也需要模拟InvokeAsync Gabe的回答有点像通过Arg。Any不能满足InvokeAsync所需的参数。然而,我并没有为此责备他,因为我花了数小时跟踪多个项目的继承链(这是一家大公司)。他无权做的事 最后,以下是成功的代码:
var estore = Substitute.For<IEntityStore>();
var dataAccessTemplate = Substitute.For<IDataAccessTemplate>();
dataAccessTemplate.InvokeAsync(context => Task.FromResult(
estore.GetEntityById<DefaultActionPlan>(
dataxs, typeof(DefaultActionPlan).FullName, new ObjectId(badPlanId))))
.ReturnsForAnyArgs(jj);
var pdp = new PlanDataProvider(dataAccessTemplate, estore);
var estore=Substitute.For();
var dataAccessTemplate=Substitute.For();
dataAccessTemplate.InvokeAsync(上下文=>Task.FromResult(
estore.GetEntityById(
dataxs,typeof(DefaultActionPlan).FullName,新对象ID(badPlanId)))
.ReturnsForayargs(jj);
var pdp=新的PlanDataProvider(dataAccessTemplate,estore);
虽然我在您的代码中看不到这一点,但我将假设GetDefaultActionPlan返回defaultActionPlan变量,并且Template.InvokeAsync是指通过构造函数传入的IDataAccessTemplate
看起来您缺少Template.InvokeAsync的模拟返回值,因为它正在包装另一个调用,所以您只关心它的返回值:
var estore = Substitute.For<IEntityStore>();
var dataAccessTemplate = Substitute.For<IDataAccessTemplate>();
dataAccessTemplate.InvokeAsync(context => Task.FromResult(Arg.Any<DefaultActionPlan>)
.ReturnsForAnyArgs(jj);
var pdp = new PlanDataProvider(dataAccessTemplate, estore);
var estore=Substitute.For();
var dataAccessTemplate=Substitute.For();
dataAccessTemplate.InvokeAsync(上下文=>Task.FromResult(Arg.Any)
.ReturnsForayargs(jj);
var pdp=新的PlanDataProvider(dataAccessTemplate,estore);
当你创建IDataAccessTemplate
的替代品时,你从未定义过它的任何方法。IsWait Template.InvokeAsync
调用InvokeAsync
的空模拟,或者实际调用带有参数的方法?我相信你让我走上了正确的道路,但仍在尝试找出模拟的一些细微差别InvokeAsync包装器…似乎与contex=>Task不一样。FromResult…似乎我需要再传递一点。太好了!我花了一些时间创建了简单的代码版本,以了解如何构造InvokeAsync模拟调用和Arg。在我的测试中,任何操作都有效。据我所知,estore.GetEntityById是否返回DefaultActionPla以外的内容反对?