【问题标题】:AutoFixture + NSubstitute throws NotASubstituteException for injected auto mockAutoFixture + NSubstitute 为注入的自动模拟抛出 NotASubstituteException
【发布时间】:2023-03-24 15:40:01
【问题描述】:

我收到以下异常:

NSubstitute.Exceptions.NotASubstituteException:像 .Received() 这样的 NSubstitute 扩展方法只能在使用 Substitute.For() 和相关方法创建的对象上调用。

...调用chargeService.When()时:

public class WhenUserTopsUpAndStripeRejectsPaymentRequest
{
    [Theory, AutoNSubstituteData]
    public void it_should_throw_AutoTopUpFailedException(
        [Frozen] StripeChargeService chargeService,
        [Frozen] IRepository repository,
        TopUpUserAccountBalance message,
        TopUpUserAccountBalanceHandler sut) <== has dependency on StripeChargeService
    {
        repository.Find(Arg.Any<ById<User>>())
            .Returns(new User
            {
                AutoTopUpEnabled = true,
                AccountBalance = -15
            });

=====>  chargeService.When(s => s.Create(Arg.Any<StripeChargeCreateOptions>()))
            .DoNotCallBase();

        Assert.Throws<AutoTopUpFailedException>(() => sut.Handle(message));
    }
}

现在,我当然可以按照 Exception 的建议手动创建 StripeChargeService,然后手动创建所有依赖项并将其注入到我的 SUT 中,但我宁愿使用更少的代码并让 AutoFixture 来解决这个问题工作。

public class AndStripeRejectsPaymentRequest
{
    [Theory, AutoNSubstituteData]
    public void it_should_throw_AutoTopUpFailedException(
        IMediator mediator,
        IBillingConfig config,
        [Frozen] IRepository repository,
        TopUpDriverAccountBalance message)
    {
        var chargeService = Substitute.ForPartsOf<StripeChargeService>("");

        repository.Find(Arg.Any<ById<Driver, TopUpDriverAccountBalanceHandler.DriverProjection>>())
            .Returns(new TopUpDriverAccountBalanceHandler.DriverProjection
            {
                AutoTopUpEnabled = true,
                AccountBalance = -15
            });

        chargeService.When(s => s.Create(Arg.Any<StripeChargeCreateOptions>()))
            .DoNotCallBase();

        // Manually build SUT, with params declared above.
        var sut = new TopUpDriverAccountBalanceHandler(mediator, repository, config, chargeService);

        Assert.Throws<AutoTopUpFailedException>(() => sut.Handle(message));
    }
}

我认为通过使用 AutoFixture.AutoNSubstitute NuGet 包中的AutoNSubstituteCustomization(),可以使用 NSubstitute 创建自动模拟参数。我做错了什么?

【问题讨论】:

    标签: autofixture nsubstitute


    【解决方案1】:

    AutoNSubstituteCustomization 仅替代 抽象。如果您需要创建一个具体类的替代品,您应该使用[Ploeh.AutoFixture.AutoNSubstitute.SubstituteAttribute] 属性显式装饰您的参数:

      [Theory, AutoNSubstituteData]
      public void it_should_throw_AutoTopUpFailedException(
          [Substitute] StripeChargeService chargeService)
      // ...
    

    请注意(至于v3.47.3)这很遗憾不能与[Frozen] 属性结合使用(请参阅相应的AutoFixture issue)。

    更新

    作为一种解决方法,您可以替换AutoNSubstituteDataAttribute 中的StripeChargeService 类型的实例(或为此创建相应的customization):

    internal class AutoNSubstituteDataAttribute : AutoDataAttribute
    {
      public AutoNSubstituteDataAttribute()
      {
        this.Fixture.Customize(new AutoNSubstituteCustomization());
    
        // Substitute an instance of the 'StripeChargeService' type
        this.Fixture.Customizations.Insert(
          0,
          new FilteringSpecimenBuilder(
            new MethodInvoker(new NSubstituteMethodQuery()),
            new ExactTypeSpecification(typeof(StripeChargeService))));
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-09
      • 2012-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多