我想编写一个单元测试来检查特定的Unity IoC对象是否已实例化。
例如,这是我正在测试的类。
using Microsoft.Practices.Unity;
using System.Threading;
namespace Client.Engine
{
public sealed class Uploader : IUploader
{
private readonly IUnityContainer _container;
public Uploader(IUnityContainer container)
{
_container = container;
}
public void PerformUpload(CancellationToken token, int batchSize)
{
token.ThrowIfCancellationRequested();
_container.Resolve<IUploadModule>("Clients").Upload(token, batchSize);
token.ThrowIfCancellationRequested();
_container.Resolve<IUploadModule>("Patients").Upload(token, batchSize);
}
}
}
这是我设置的单元测试
[TestClass()]
public class UploadClientsTests : UploadModuleTestsBase
{
[TestMethod()]
public override void UploaderRegrestrationTest()
{
PerformRegistrationTest("Clients");
}
}
[TestClass()]
public class UploadPatientsTests : UploadModuleTestsBase
{
[TestMethod()]
public override void UploaderRegrestrationTest()
{
PerformUpladerRegistrationTest("Patients");
}
}
public class UploadPatientsTests : UploadModuleTestsBase
{
protected static void PerformUpladerRegistrationTest(string moduleName)
{
var container = new UnityContainer();
var mocker = new AutoMoqer(container);
var random = new Random();
int batchSize = random.Next(int.MaxValue);
var token = new CancellationToken();
var uploadModuleMock = new Mock<IUploadModule>();
uploadModuleMock.Setup(module => module.Upload(token, batchSize)).Verifiable();
container.RegisterInstance(typeof(IUploadModule), moduleName, uploadModuleMock.Object, new ContainerControlledLifetimeManager());
container.RegisterInstance(typeof(IUploadModule), Mock.Of<IUploadModule>());
var uploader = mocker.Resolve<Uploader>();
uploader.PerformUpload(token, batchSize);
uploadModuleMock.Verify();
}
}
我遇到的问题是,如果命名类型不可用,Unity 2.0 不会回退到默认实例。因此,如果我注释掉客户测试完美工作的_container.Resolve<IUploadModule>("Patients")
行,如果我注释掉患者测试完美_container.Resolve<IUploadModule>("Clients")
,我只是不知道如何使两者可以共存。
编辑:在正常操作中,我像这样重新串起两个对象。
public static Bootstrap(IUnityContainer container)
{
container.RegisterType<IUploadModule, UploadClients>("Clients", new HierarchicalLifetimeManager());
container.RegisterType<IUploadModule, UploadPatients>("Patients", new HierarchicalLifetimeManager());
}
为什么不直接模拟IUnityContainer
,而不是使用真正的 UnityContainer?
从对PerformUpload
方法进行单元测试的角度来看,您应该只断言确实调用了Resolve<>
方法和Upload
方法并具有相应的参数。不是 Unity 如何解析的实际内部结构。
事实上,您甚至可以删除对IUnityContainer
的依赖,并让您的构造函数接收一个工厂方法,您可以在 Unity 中注册该方法。我倾向于避免这种依赖关系,并将工厂直接声明为Func<string, IUploadModule>
。
以下示例未经测试,但类似以下内容可能有效:
container.RegisterType<Func<string, IUploadModule>>(new InjectionFactory(c =>
new Func<string, IUploadModule>(name =>
c.Resolve<IUploadModule>(name)
)
)
);
这是一个额外的注册。您还必须像现在一样注册上传者。
注册后,您可以让构造函数使用 Func<string, IUploadModule>
作为参数:
public Uploader(Func<string, IUploadModule> factory)
{
_factory = factory;
}
并通过以下方式调用它以获取您的上传者:
_factory("Patients");
在没有看到您的应用程序中的所有内容是如何设计的,IMO 我认为您的Uploader
类应该稍微重组一下。 PerformUpload
方法具有要IUploadModule
的依赖项,但不是像 IoC 那样将它们作为依赖项,而是在 Uploader
中手动解析它们。 如果你有一个新的IUploadModule
,你将不得不改变你的PerformUpload
方法,这有点违背了做IoC的目的。
我的建议是这样的:
using Microsoft.Practices.Unity;
using System.Threading;
namespace Client.Engine
{
public sealed class Uploader : IUploader
{
public Uploader()
{
}
public void PerformUpload(IUploadModule uploadModule, CancellationToken token, int batchSize)
{
token.ThrowIfCancellationRequested();
uploadModule.Upload(token, batchSize);
}
}
}
这也将简化单元测试。
[TestMethod()]
public void PerformUpladerRegistrationTest()
{
var random = new Random();
int batchSize = random.Next(int.MaxValue);
var token = new CancellationToken();
var uploadModuleMock = new Mock<IUploadModule>();
uploadModuleMock.Setup(module => module.Upload(token, batchSize)).Verifiable();
uploader.PerformUpload(uploadModuleMock.Object, token, batchSize);
uploadModuleMock.Verify();
}