AutoFixture + NSubstitute 为注入的自动模拟抛出 NotASubstituteException
AutoFixture + NSubstitute throws NotASubstituteException for injected auto mock
我收到以下异常:
NSubstitute.Exceptions.NotASubstituteException: NSubstitute extension methods like .Received() can only be called on objects created using Substitute.For() and related methods.
...调用 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 创建自动模拟参数 。我做错了什么?
AutoNSubstituteCustomization
仅替代 抽象 。如果您需要创建具体 class 的替代品,您应该使用 [Ploeh.AutoFixture.AutoNSubstitute.SubstituteAttribute]
属性显式修饰您的参数:
[Theory, AutoNSubstituteData]
public void it_should_throw_AutoTopUpFailedException(
[Substitute] StripeChargeService chargeService)
// ...
请注意(至于v3.47.3) this unfortunately does not work in combination with the [Frozen]
attribute (see the corresponding 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))));
}
}
我收到以下异常:
NSubstitute.Exceptions.NotASubstituteException: NSubstitute extension methods like .Received() can only be called on objects created using Substitute.For() and related methods.
...调用 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 创建自动模拟参数 。我做错了什么?
AutoNSubstituteCustomization
仅替代 抽象 。如果您需要创建具体 class 的替代品,您应该使用 [Ploeh.AutoFixture.AutoNSubstitute.SubstituteAttribute]
属性显式修饰您的参数:
[Theory, AutoNSubstituteData]
public void it_should_throw_AutoTopUpFailedException(
[Substitute] StripeChargeService chargeService)
// ...
请注意(至于v3.47.3) this unfortunately does not work in combination with the [Frozen]
attribute (see the corresponding 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))));
}
}