c# - 尽管定义了返回对象,NSubstitute Async 仍返回 null

标签 c# unit-testing asynchronous

我有一个单元测试应该返回指定的对象,但它返回了 null。

要测试的数据提供者:

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

测试:

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

无论如何 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);

最佳答案

虽然我在您的代码中没有看到这一点,但我会假设 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);

关于c# - 尽管定义了返回对象,NSubstitute Async 仍返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37837826/

相关文章:

ios - swift iOS 从异步中获取值(value)(发布数据)

c# - "await/async": Why the 2 pieces of code doesn't run the same?

javascript - 为什么这个 'feelings' 显示为一个对象,而不是我在文本字段中输入的内容?

c# - 在 C# 中将 Func 与任务一起使用

c# - 需要C#中的代码解释

C# 从网站抓取数据

javascript - Jest 将 MomentJS 导入到未弹出的 React 应用程序中

c# - 当用户在最后一行的最后一个单元格上按 Enter 键时,向 DataGrid 添加新行

angular - FakeAsync/tick (Async/whenStable) 与 detectChanges()

python - 如何将文件的局部变量导入到当前模块