I'm receiving the following Exception:
NSubstitute.Exceptions.NotASubstituteException: NSubstitute extension methods like .Received() can only be called on objects created using Substitute.For() and related methods.
...when calling 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));
}
}
Now, I can of course get around this by doing as the Exception suggests and manually create the StripeChargeService, and then manually create and inject all my dependencies into my SUT, but I'd rather have less code and let AutoFixture do the work.
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));
}
}
I thought that by using the AutoNSubstituteCustomization()
in the AutoFixture.AutoNSubstitute NuGet package, auto-mocked parameters would be created using NSubstitute. What am I doing wrong?
The AutoNSubstituteCustomization
substitutes abstractions only. If you need to create a substitute for a concrete class you should decorate your parameter with the [Ploeh.AutoFixture.AutoNSubstitute.SubstituteAttribute]
attribute explicitly:
[Theory, AutoNSubstituteData]
public void it_should_throw_AutoTopUpFailedException(
[Substitute] StripeChargeService chargeService)
// ...
Please note that (as for v3.47.3) this unfortunately does not work in combination with the [Frozen]
attribute (see the corresponding AutoFixture issue).
UPDATED
As a workaround you may substitute an instance of the StripeChargeService
type in the AutoNSubstituteDataAttribute
(or create a corresponding customization for this purpose):
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))));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With