Используя Ninject MockingKernel Moq, как внедрить несколько макетов для одного и того же интерфейса

1

Класс С#, который я хочу протестировать, принимает экземпляры IEnumerable одного и того же интерфейса. Я использую Ninject для инъекции зависимостей. Как я должен вводить mocks в IEnumerable, используя Ninject MockingKernel Moq

public class Foo: IFoo
{
    private readonly Dictionary<ContextType, IBar> _bars;
    public Foo(IEnumerable<IBar> bars)
    {
        _bars= bars.ToDictionary(x => x.ContextType);
    }
}
public interface IBar
{
    ContextType ContextType { get; }
    void DoStuff();
}
public enum ContextType
{
    Local,
    Site,
    Test
}

Так выглядит мое регулярное связывание

//assume _kernel is StandardKernel
_kernel.Bind<IFoo>().To<MyFoo>();
_kernel.Bind<IBar>().To<Bar1>(); //ContextType.Site
_kernel.Bind<IBar>().To<Bar2>(); //ContextType.Local
_kernel.Bind<IBar>().To<Bar3>(); //ContextType.Test

Настройка mocks, как показано ниже, вводит только последний макет в Foo (как предполагается, впрыскивание 3 mocks)

//using _kernel = new MoqMockingKernel()
_kernel.Bind<IFoo>().To<MyFoo>();
var bar1Mock = _kernel.GetMock<IBar>();barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site);
var bar2Mock = _kernel.GetMock<IBar>();barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local);
var bar3Mock = _kernel.GetMock<IBar>();barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test);

_foo = _kernel.Get<IFoo>();

Любая помощь приветствуется. благодаря

  • 0
    При двойном связывании с одним и тем же интерфейсом вы фактически переопределяете предыдущее связывание, а не добавляете новое. Таким образом, на самом деле, тип «Bar3» будет создан при разрешении «IBar» в любом месте кода. Можете ли вы объяснить более четко, что вы пытаетесь достичь?
  • 0
    У меня есть шаблон стратегии, реализованный со свойством IBar ContextType в качестве ключа. Итак, я внедряю несколько стратегий (Bars) в Foo и хотел бы вводить макеты для каждой стратегии во время тестирования.
Теги:
unit-testing
moq
ninject
ninject-mockingkernel

3 ответа

0

Запуск в ту же проблему. Ответы выше не помогли. Ниже приведено одно решение, но оно не идеально.

Использование kernel.Reset(); не кажется правильным.

Код как

var bar1Mock = _kernel.GetMock<IBar()
barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site);
var bar2Mock = _kernel.GetMock<IBar>(); 
barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local);
var bar3Mock = _kernel.GetMock<IBar>(); 
barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test);

_kernel.Bind<IBar>().ToMethod( x => bar1Mock.Object); 
_kernel.Bind<IBar>().ToMethod( x => bar2Mock.Object);
_kernel.Bind<IBar>().ToMethod( x => bar3Mock.Object);

foo = _kernel.Get<IFoo>();

Все еще возвращает ссылку на тот же (последний) макет. Может, я что-то упустил?

Я хочу использовать насмешливое ядро, но пока лучшее, что я получил, это:

var barMock1 = new Moq.Mock<IBar>();
barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site);

var barMock2 = new Moq.Mock<IBar>();
barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local);

var bar1Mock3 = new Moq.Mock<IBar>();
barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test);

 _kernel.Bind<IBar>().ToMethod(s => barMock1.Object);
 _kernel.Bind<IBar>().ToMethod(s => barMock2.Object);
 _kernel.Bind<IBar>().ToMethod(s => barMock3.Object);

Это должно работать для более или менее простых объектов, но если в Ibar есть зависимости, нам придется решать вручную и использовать ninject для этого. Итак, какие-нибудь лучшие идеи, как заставить разные объекты издеваться или каким-то образом установить "область"?

0

Сейчас у меня это работает. _kernel необходимо сбросить до того, как будет запрошен другой уникальный макет того же интерфейса. Этот код ниже работает

var bar1Mock = _kernel.GetMock<IBar();barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site);
_kernel.Reset();

var bar2Mock = _kernel.GetMock<IBar>();barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local);
_kernel.Reset();

var bar3Mock = _kernel.GetMock<IBar>(); barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test);
_kernel.Reset();

_kernel.Bind<IBar>().ToConstant(bar1Mock.Object); 
_kernel.Bind<IBar>().ToConstant(bar2Mock.Object);
_kernel.Bind<IBar>().ToConstant(bar3Mock.Object);

благодаря

0

Почему бы просто не создать экземпляр Foo вручную, если вы его тестируете?

var bar1Mock = _kernel.GetMock<IBar();
barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site);
var bar2Mock = _kernel.GetMock<IBar>(); 
barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local);
var bar3Mock = _kernel.GetMock<IBar>(); 
barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test);

// simply create new instance, what is a point o
var target = new Foo(new[]{barMock1.Object, bar2Mock.Object, bar3Mock.Object });

Но если вы понимаете, что правильно, вы хотите, чтобы IEnumerable<IBar> bars заполнялись Ninject? Затем вам нужно привязать фактическую коллекцию, используя Ninject:

var allBars = new []{new Bar1(), new Bar2(), new Bar3()};
kernel.Bind<IEnumerable<IBar>>().ToConstant(allBars);

Или, попробуйте фактически массив IBar вместо IEnumerable<IBar>, и оставьте свою привязку как есть:

_kernel.Bind<IFoo>().To<MyFoo>();
_kernel.Bind<IBar>().To<Bar1>(); //ContextType.Site
_kernel.Bind<IBar>().To<Bar2>(); //ContextType.Local
_kernel.Bind<IBar>().To<Bar3>(); 

public class Foo: IFoo
{
    private readonly Dictionary<ContextType, IBar> _bars;
    public Foo(IBar[] bars)
    {
        _bars= bars.ToDictionary(x => x.ContextType);
    }
}

Согласно руководству, это должно сработать.

Обновление: привязка к фактическим макетным экземплярам и после разрешения IFoo, как обычно:

 var bar1Mock = _kernel.GetMock<IBar();
 barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site);
 var bar2Mock = _kernel.GetMock<IBar>(); 
 barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local);
 var bar3Mock = _kernel.GetMock<IBar>(); 
 barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test);

_kernel.Bind<IBar>().ToConstant(bar1Mock.Object); 
_kernel.Bind<IBar>().ToConstant(bar2Mock.Object);
_kernel.Bind<IBar>().ToConstant(bar3Mock.Object);

foo = _kernel.Get<IFoo>();

Обновление2: попробуйте этот путь

_kernel.Bind<IBar>().ToMethod( x => bar1Mock.Object); 
_kernel.Bind<IBar>().ToMethod( x => bar2Mock.Object);
_kernel.Bind<IBar>().ToMethod( x => bar3Mock.Object);
  • 0
    Я мог бы просто создать новый экземпляр Foo вручную, но я бы хотел, чтобы Ninject справился с этим. Также по иронии судьбы создание нового Foo вручную путем передачи массива barMock. Объекты 1, 2 и 3 - не работали. Все три были последнего типа теста
  • 0
    Есть ли успехи у конструктора IBar[] bars ?
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню