Structure Map Automocker Inject如何工作?

时间:2013-04-02 09:53:06

标签: c# unit-testing structuremap rhino-mocks automocking

我有包含IEnumerable参数的构造函数。当我尝试将具体对象注入automocker时,它不会被使用。

当我使用包含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。实际:&℃,GT;

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 个答案:

答案 0 :(得分:2)

看了the source code for the AutoMocker<TTargetClass> class后,我注意到以下内容:

  • 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>类,可以在the same file中找到(最后)。

好的,说得够多。我不确定我的解释是否足够清楚,所以下面是两个测试通过的代码。希望这能澄清一切:

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