AutoFixture + NSubstitute为注入的自动模拟抛出NotASubstituteException

时间:2016-06-03 03:19:42

标签: autofixture nsubstitute

我收到以下例外:

  

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

现在,我可以通过执行异常建议并手动创建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创建自动模拟参数 。我做错了什么?

1 个答案:

答案 0 :(得分:4)

AutoNSubstituteCustomization仅替换抽象。如果您需要创建具体类的替代品,则应明确使用[Ploeh.AutoFixture.AutoNSubstitute.SubstituteAttribute]属性修饰参数:

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

请注意(对于v3.47.3),遗憾的是,这与[Frozen]属性无关(请参阅相应的自动翻译issue)。

<强>已更新

作为一种解决方法,您可以替换 StripeChargeService中的AutoNSubstituteDataAttribute类型的实例(或为此目的创建相应的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))));
  }
}