Structure Map Automocker Inject如何工作? [英] How Structure Map Automocker Inject works?

查看:123
本文介绍了Structure Map Automocker Inject如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有包含IEnumerable参数的构造函数.当我尝试将具体对象注入自动模拟时,不使用它.

I have constructor containing IEnumerable parameter. When I try to Inject concrete object to automocker it is not used.

当我使用包含IEnumerable属性的包装器类时,所有的工作都按预期进行.

When I use wrapper class containing IEnumerable property all works as expected.

如何测试TestClass1?

How can I test TestClass1?

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>.

Assert.AreEqual failed. Expected:<1>. Actual:<0>.

包装器类参数

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

测试结果为:

成功.

推荐答案

看看

After taking a look at the source code for the AutoMocker<TTargetClass> class, I noticed the following:

  • AutoMocker在幕后使用了一个StructureMap容器​​
  • 通常所有依赖关系都是使用容器直接解决的
  • 类型为IEnumerable<T>的依赖项将得到不同的对待(请参见下文)
  • AutoMocker uses a StructureMap container under the covers
  • usually all dependencies are directly resolved using the container
  • dependencies that are of type IEnumerable<T> are treated differently (see below)

这是AutoMocker<TTargetClass>类中的一段代码,显示了如何解决构造函数依赖关系(为简洁起见,我删除了几行):

Here's a piece of code from the AutoMocker<TTargetClass> class that shows how constructor dependencies are resolved (I removed some lines for brevity):

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

The code shows that dependencies are usually resolved using _container.GetInstance, but there are two exceptions: ararys and IEnumerable<>s

对于IEnumerable<T>,事实证明使用了_container.GetAllInstances(typeof(T)).这意味着您应该注入几个IItem实例,而不是IEnumerable<IItem>.负责此操作的代码是EnumerableBuilder<T>类,可在

For IEnumerable<T>, it turns out that _container.GetAllInstances(typeof(T)) is used. This meas that in your case you should inject several IItem instances, not an IEnumerable<IItem>. The code responsible for this is the EnumerableBuilder<T> class, whih can be found in the same file (at the end).

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

OK, enough talk. I'm not sure if my explanation is clear enough, so below is code for two tests that pass. Hopefully that will clarify everything:

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

这篇关于Structure Map Automocker Inject如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆