2016-06-03 14 views
4

ich die folgende Ausnahme bin Empfang:AutoFixture + NSubstitute wirft NotASubstituteException für injizierte Auto Mock

NSubstitute.Exceptions.NotASubstituteException: NSubstitute Erweiterungsmethoden wie .Received() kann nur auf Objekte aufgerufen werden Substitute erstellt. Für() und verwandte Methoden.

... wenn chargeService.When() aufrufen:

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

Nun, ich kann natürlich dieses Problem umgehen, indem Sie als die Ausnahme schlägt und manuell die StripeChargeService erstellen und dann manuell erstellen und injiziere alle meine Abhängigkeiten in mein SUT, aber ich würde lieber weniger Code haben und AutoFixture die Arbeit machen lassen.

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

Ich dachte, dass die AutoNSubstituteCustomization() im AutoFixture.AutoNSubstitute NuGet Paket, Auto-verspottete Parameter würde NSubstitute werden erstellt unter Verwendung. Was mache ich falsch?

Antwort

4

Die AutoNSubstituteCustomization ersetzt Abstraktionen nur. Wenn Sie einen Ersatz für eine konkrete Klasse erstellen müssen, sollten Sie Ihren Parameter mit dem [Ploeh.AutoFixture.AutoNSubstitute.SubstituteAttribute] Attribute schmücken ausdrücklich:

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

Bitte beachten, dass (wie bei v3.47.3) dies leider nicht funktioniert in Kombination mit dem [Frozen] Attribute (siehe die entsprechende AutoFixture issue).

AKTUALISIERT

Als Abhilfe können Sie können Ersatz eine Instanz des StripeChargeService Typ im AutoNSubstituteDataAttribute (oder eine entsprechende customization zu diesem Zweck erstellen):

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