2

我有包含 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>。实际:<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());
}

测试结果是:

成功。

4

1 回答 1

3

在查看了该类的源代码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());
}
于 2013-04-02T15:02:42.063 回答