Как работает карта структуры Automocker Inject?

У меня есть конструктор, содержащий параметр IEnumerable. Когда я пытаюсь ввести конкретный объект в автомокер, он не используется.

Когда я использую класс-оболочку, содержащую свойство IEnumerable, все работает как положено.

Как я могу проверить TestClass1?

IEnumerable параметр

public class TestClass1
{
    public TestClass1(IEnumerable<IItem> items)
    {
        Items = items;
    }

    public IEnumerable<IItem> Items { get; private set; }
}

[TestMethod]
public void TestClass1Constructor()
{
    RhinoAutoMocker<TestClass1> autoMocker = new RhinoAutoMocker<TestClass1>();

    IEnumerable<IItem> items = new[] { MockRepository.GenerateMock<IItem>() };
    autoMocker.Inject(items);

    Assert.AreEqual(1, autoMocker.ClassUnderTest.Items.Count());
}

Результат теста:

Assert.AreEqual не удалось. Ожидаемое:<1>. Фактическое:<0>.

Параметр класса Wrapper

public class TestClass2
{
    public TestClass2(WrapperClass numbersWrapper)
    {
        Items = numbersWrapper.Items;
    }

    public IEnumerable<IItem> Items { get; private set; }
}

[TestMethod]
public void TestClass2Constructor()
{
    RhinoAutoMocker<TestClass2> autoMocker = new RhinoAutoMocker<TestClass2>();

    WrapperClass numbers = new WrapperClass(new[] { MockRepository.GenerateMock<IItem>() });
    autoMocker.Inject(numbers);

    Assert.AreEqual(1, autoMocker.ClassUnderTest.Items.Count());
}

Результат теста:

Успех.

1 ответ

Решение

Посмотрев на исходный код AutoMocker<TTargetClass> класс, я заметил следующее:

  • AutoMocker использует контейнер StructureMap под крышками
  • обычно все зависимости решаются напрямую с помощью контейнера
  • зависимости, которые имеют тип IEnumerable<T> обрабатываются по-разному (см. ниже)

Вот кусок кода из AutoMocker<TTargetClass> Класс, который показывает, как разрешаются зависимости конструктора (для краткости я удалил несколько строк):

private object[] getConstructorArgs()
{
    ConstructorInfo ctor = Constructor.GetGreediestConstructor(typeof (TTargetClass));
    var list = new List<object>();
    foreach (ParameterInfo parameterInfo in ctor.GetParameters())
    {
        Type dependencyType = parameterInfo.ParameterType;

        if (dependencyType.IsArray)
        {
            [...]
        }
        else if (dependencyType.Closes(typeof (IEnumerable<>)))
        {
            Type @interface = dependencyType.FindFirstInterfaceThatCloses(typeof (IEnumerable<>));
            Type elementType = @interface.GetGenericArguments().First();

            // Here's the interesting code:
            var builder = typeof (EnumerableBuilder<>).CloseAndBuildAs<IEnumerableBuilder>(_container,
                                                                                           elementType);
            list.Add(builder.ToEnumerable());
        }
        else
        {
            object dependency = _container.GetInstance(dependencyType);
            list.Add(dependency);
        }
    }

    return list.ToArray();
}

Код показывает, что зависимости обычно разрешаются с помощью _container.GetInstance, но есть два исключения: ararys и IEnumerable<> s

За IEnumerable<T>, Оказывается, что _container.GetAllInstances(typeof(T)) используется. Это означает, что в вашем случае вы должны ввести несколько IItem случаи, а не IEnumerable<IItem>, Код, ответственный за это EnumerableBuilder<T> класс, который можно найти в том же файле (в конце).

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

[Test]
public void Test_OneItem()
{
    var autoMocker = new RhinoAutoMocker<TestClass1>();

    autoMocker.Inject(MockRepository.GenerateMock<IItem>());

    Assert.AreEqual(1, autoMocker.ClassUnderTest.Items.Count());
}

[Test]
public void Test_TwoItems()
{
    var autoMocker = new RhinoAutoMocker<TestClass1>();

    autoMocker.Inject(MockRepository.GenerateMock<IItem>());
    autoMocker.Inject(MockRepository.GenerateMock<IItem>());

    Assert.AreEqual(2, autoMocker.ClassUnderTest.Items.Count());
}
Другие вопросы по тегам