Ninject 和动态 WithConstructor/WithMeta 和 RhinoMocks
在我的项目中,我有一个 IoC 容器,它通过 ServiceModule 以通常的方式进行初始化。当我编写单元测试时,我希望能够绑定到 StrictMock、DynamicMock、PartialMock 或 Stub。过去,我有一个 FakeServiceModule 可以将所有内容绑定到 StrictMocks,但这是非常严格的,我想扩展它以允许创建我选择的模拟类型。
为了实现这一目标,我创建了以下内容。
public class NinjectMocking
{
public Type TypeToMock { get; set; }
public MockType MockTypeToUse { get; set; }
public IBindingWithOrOnSyntax<Type> BindingWithOrOnSyntax { get; set; }
}
public enum MockType
{
Stub,
Strict,
Dynamic,
Partial
}
我的想法是,我将像这样初始化假服务模块:
foreach (var mockType in _mocks)
{
object ninjaMock;
switch (mockType.MockTypeToUse)
{
case MockType.Strict:
{
ninjaMock = _mockRepository.StrictMock(mockType.TypeToMock);
break;
}
case MockType.Dynamic:
{
ninjaMock = _mockRepository.DynamicMock(mockType.TypeToMock);
break;
}
case MockType.Partial:
{
ninjaMock = _mockRepository.PartialMock(mockType.TypeToMock);
break;
}
case MockType.Stub:
{
ninjaMock = _mockRepository.Stub(mockType.TypeToMock);
break;
}
default:
{
ninjaMock = _mockRepository.StrictMock(mockType.TypeToMock);
break;
}
}
if (mockType.BindingWithOrOnSyntax == typeof(ConstructorArgument))
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock).w
.WithConstructorArgument(mockType.BindingWithOrOnSyntax);
else
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock);
}
已经使用模拟列表进行了初始化...
NinjectMocking ninjectMocking = new NinjectMocking();
ninjectMocking.TypeToMock = typeToAdd;
ninjectMocking.MockTypeToUse = MockType.Dynamic;
这一切都运行得很好。然而,问题来了,我们的一些绑定需要 .WithConstructorArgument 或 .WithMetaData ,也许
Bind<ISomeRepository>().ToMethod(m => someRepository)
.WithConstructorArgument("context", ctx => new TestDataContext());
将来还会需要其他一些。这就是为什么我在 NinjectMocking 类中有 BindingWithOrOnSyntax 属性。所以我的新初始化程序可能看起来像这样:
NinjectMocking ninjectMocking = new NinjectMocking();
ninjectMocking.TypeToMock = typeToAdd;
ninjectMocking.MockTypeToUse = MockType.Dynamic;
ninjectMocking.BindingWithOrOnSyntax.WithConstructorArgument("context", constructorArgument);
问题是我不知道如何让它在绑定中使用它。我想做的是类似
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock).[WhatGoesHere]
我真的不知道如何使用 [WhatGoesHere] 位来做到这一点,或者如何定义Bind 以便它使用我在 BindingWithOrOnSyntax 属性中传入的任何内容。我最后一次绝望的尝试是尝试通过类似的方法来强制它
if (mockType.BindingWithOrOnSyntax == typeof(ConstructorArgument))
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock)
.WithConstructorArgument(mockType.BindingWithOrOnSyntax);
,但这显然行不通。
任何指向正确方向的指针,或者即使有更好的方法来实现这一点,都将不胜感激。
In my project I have an IoC container that gets initialized the usual way with a ServiceModule. When I write unit tests, I want to be able to bind to either a StrictMock, DynamicMock, PartialMock or Stub. In the past I had a FakeServiceModule that would bind everything to StrictMocks, but this is very restrictive, and I wanted to expand this to allow creating a mock type of my choosing.
To achieve this I created the following.
public class NinjectMocking
{
public Type TypeToMock { get; set; }
public MockType MockTypeToUse { get; set; }
public IBindingWithOrOnSyntax<Type> BindingWithOrOnSyntax { get; set; }
}
public enum MockType
{
Stub,
Strict,
Dynamic,
Partial
}
The idea is that I would initialise the fake service module like so:
foreach (var mockType in _mocks)
{
object ninjaMock;
switch (mockType.MockTypeToUse)
{
case MockType.Strict:
{
ninjaMock = _mockRepository.StrictMock(mockType.TypeToMock);
break;
}
case MockType.Dynamic:
{
ninjaMock = _mockRepository.DynamicMock(mockType.TypeToMock);
break;
}
case MockType.Partial:
{
ninjaMock = _mockRepository.PartialMock(mockType.TypeToMock);
break;
}
case MockType.Stub:
{
ninjaMock = _mockRepository.Stub(mockType.TypeToMock);
break;
}
default:
{
ninjaMock = _mockRepository.StrictMock(mockType.TypeToMock);
break;
}
}
if (mockType.BindingWithOrOnSyntax == typeof(ConstructorArgument))
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock).w
.WithConstructorArgument(mockType.BindingWithOrOnSyntax);
else
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock);
}
Having been initliazed with a list of mocks...
NinjectMocking ninjectMocking = new NinjectMocking();
ninjectMocking.TypeToMock = typeToAdd;
ninjectMocking.MockTypeToUse = MockType.Dynamic;
This all works perfectly. However, and here comes the question, some of our bindings need either .WithConstructorArgument or .WithMetaData as in
Bind<ISomeRepository>().ToMethod(m => someRepository)
.WithConstructorArgument("context", ctx => new TestDataContext());
and maybe some others in the future. That is why I have the BindingWithOrOnSyntax property in the NinjectMocking class. So my new initializer may look something like this:
NinjectMocking ninjectMocking = new NinjectMocking();
ninjectMocking.TypeToMock = typeToAdd;
ninjectMocking.MockTypeToUse = MockType.Dynamic;
ninjectMocking.BindingWithOrOnSyntax.WithConstructorArgument("context", constructorArgument);
The problem is I don't know how to make it use that in the binding. What I would like to do is something like
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock).[WhatGoesHere]
I don't really know how to do it with the [WhatGoesHere] bit, or how else to define the Bind so that it uses whatever I pass in, in the BindingWithOrOnSyntax property. My last desperate attempt was to try force it via something like
if (mockType.BindingWithOrOnSyntax == typeof(ConstructorArgument))
Bind(mockType.TypeToMock).ToMethod(m => ninjaMock)
.WithConstructorArgument(mockType.BindingWithOrOnSyntax);
But that obviously doesn't work.
Any pointers in the right direction, or even if there is a better way to achieve this, would be greatly appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在单元测试期间不要使用 IOC 容器。 IOC 容器将在运行时用于将依赖项注入到组件中。在单元测试期间,您使用模拟/存根依赖项创建组件。如果您的组件直接从 IOC 容器解析依赖关系,则您没有正确使用该容器。
Don't use an IOC container during unit testing. An IOC container is to be used at runtime to inject your dependencies into your components. During unit testing, you create your components with mocked/stubbed dependencies. If your components are resolving dependencies directly from the IOC container, you're not using the container properly.