2016-06-03 2 views
4

Я получаю следующее исключение:AutoFixture + NSubstitute бросает NotASubstituteException для впрыскиваемого авто макетом

NSubstitute.Exceptions.NotASubstituteException: NSubstitute методы расширения, как .Received() могут быть вызваны только на объекты, созданные с помощью Substitute. Для() и связанных с ним методов.

... при вызове 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)); 
    } 
} 

Я думал, что с помощью AutoNSubstituteCustomization() в пакете AutoFixture.AutoNSubstitute NuGet, параметры авто-издевался бы быть создан с помощью NSubstitute. Что я делаю не так?

ответ

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)))); 
    } 
} 
Смежные вопросы