2015-11-13 1 views
5

Рассмотрим следующие классы:Вводят Оба интерфейса и реализации в AutoFixture

public interface IInterface {} 
public class Class : IInterface {} 

public class Customization : ICustomization 
{ 
    readonly IInterface item; 

    public Customization() : this(new Class()) {} 

    public Customization(IInterface item) 
    { 
     this.item = item; 
    } 

    public void Customize(IFixture fixture) 
    { 
     fixture.Inject(item); 
     var created = fixture.Create<Class>(); // Would like this to resolve as item from previous line. 
    } 
} 

Проблема Я бегу в том, что IInterface впрыскивается, в то время как Class нет. Есть ли способ вставить как IInterface, так и Class, чтобы тот же экземпляр был возвращен для обоих?

Обратите внимание, что я хотел бы сделать это, используя ICustomization (или в пределах ICustomization), а не с атрибутами тестового метода. Я ищу, чтобы сделать индивидуальные инъекции на этих двух классах. Если я использую [Frozen(Matching.ImplementedInterfaces)]Class item в качестве параметра, он не работает, так как класс, который является Frozen, перезаписывает введенное значение в методе ICustomization.Customize.

Обратите внимание, что это пример кода, а не как я его использую. В методике испытаний XUnit, я хотел бы Class экземпляр, указанный в качестве параметра будет замороженный IInstance выше:

public void MyTest(IInterface @interface, Class implementation) 
{ 
    Assert.Same(@interface, implementation); 
} 
+1

Эта перегрузка 'Freeze' не делает то, что вы думаете, что она делает; см. [документация] (https://github.com/AutoFixture/AutoFixture/blob/master/Src/AutoFixture/FixtureFreezer.cs#L43-L72). См. Ответ Энрико Кампидоглио для одного довольно идиоматического способа достижения желаемого результата. Другим вариантом было бы использование одного из расширений Auto-mocking для AutoFixture, которые в основном имеют встроенные функции. –

+0

Извинения @MarkSeemann, я терплю неудачу. Я видел другую дискуссию о Inject/Freeze и запутался. Я имел в виду Inject, а не Freeze, и обновил вопрос соответствующим образом. –

ответ

0

ОК, это потребовалось навсегда, чтобы выяснить, но этот вопрос/сценарий в конечном итоге из-за плохого дизайна с моей стороны и неопытности и обучения AutoFixture. Фактический сценарий того, что я пытался сделать, это зарегистрировать контейнер IoC с моим устройством, и я хотел, чтобы IServiceLocator и его реализация были зарегистрированы в Fixture, чтобы они были доступны для ввода значений в текущий метод тестирования.

Это решение было разрешено путем добавления a Customization для передачи запросов предоставленному IServiceLocator (также упоминалось here in this question).

Кроме того, я сделал an extension method, который использует Dynamitey, который делает то, что я искал, но он больше не используется, и я, вероятно, удалю в какой-то момент.

Таким образом, ответ: , если вы хотите сделать это по какой-то причине, вы более чем вероятно. Я на полпути соблазн удалить этот ответ, но я оставлю его здесь, если другой newb, как я, сталкивается с той же проблемой и может извлечь из этого выгоду.

Наконец, я хотел бы поблагодарить @ enrico-campidoglio и @ mark-seemann за их терпение и действительно информативные/качественные ответы/помощь (а также за то, что никто не голосовал за этот вопрос). Я знаю, что в баре установлено высокое значение @ Stack Overflow, и я, вероятно, должен был немного больше терпения, прежде чем публиковать этот вопрос.

2

Конечно, вы можете применить атрибут параметра конкретного класса [Frozen] и указать ImplementedInterfaces в качестве соответствия критерии:

[Theory, AutoData] 
public void Test(
    [Frozen(Matching.ImplementedInterfaces)]Class implementation, 
    IInterface @interface) 
{ 
    Assert.Same(implementation, @interface); 
} 

это говорит AutoFixture обеспечить жеClass экземпляра каждый раз, когда он должен создать значение для любого из его реализации ed интерфейсов.

+0

Благодарим вас за ответ, @ enrico-campidoglio. Я прошу прощения за то, что не яснее, я ищу Inject, а не Freeze. Кроме того, я ищу Inject внутри ICustomization, а не на уровне атрибута. Я уточнил этот вопрос, чтобы быть более кратким/точным. Пожалуйста, извините мою новизну! –

4

Если Вы абсолютно должны сделать это сами

Если присмотреться к методу Inject, вы заметите, что на самом деле это общий метод, но о том, что тип аргумента выводится, когда вы используете его, как вы его используете , Если вы хотите заморозить оба, вы можете - вам просто нужно вызывать Inject для каждого типа.

Ниже приведено небольшое изменение Customization. Для того чтобы предотвратить возможно недопустимое Downcast, я изменил его так, чтобы его item поле (и соответствующий item конструктор аргумент) имеет тип Class:

public class Customization : ICustomization 
{ 
    readonly Class item; 

    public Customization() : this(new Class()) { } 

    public Customization(Class item) 
    { 
     this.item = item; 
    } 

    public void Customize(IFixture fixture) 
    { 
     fixture.Inject(item); 
     fixture.Inject<IInterface>(item); 
    } 
} 

Обратите внимание, что Customize впрыскивает один и тот же элемент дважды. В первой строке аргумент generic type выводится компилятором Class, тогда как во второй строке аргумент типа IInterface явно определен.

Учитывая это реализация, следующий тест пройден:

[Fact] 
public void UseCustomization() 
{ 
    var fixture = new Fixture().Customize(new Customization()); 

    var c = fixture.Create<Class>(); 
    var i = fixture.Create<IInterface>(); 

    Assert.Equal(c, i); 
} 

Использование встроенного API

Все, что сказал, я считаю, что легче просто использовать встроенный API:

[Fact] 
public void UseTypeRelay() 
{ 
    var fixture = new Fixture(); 
    fixture.Customizations.Add(
     new TypeRelay(
      typeof(IInterface), 
      typeof(Class))); 
    fixture.Freeze<Class>(); 

    var c = fixture.Create<Class>(); 
    var i = fixture.Create<IInterface>(); 

    Assert.Equal(c, i); 
} 

TypeRelay карты IInterface к Class, что означает, что все запросы на IInterface будут переданы на запросы F или Class.Когда Class заморожен, это означает, что не только Class заморожен, но и IInterface.

Смежные вопросы