Structure Map Automocker Inject如何工作? [英] How Structure Map Automocker Inject works?
问题描述
我有包含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屋!