1

我想编写一个单元测试来检查特定的 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());
}
4

2 回答 2

3

为什么不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");
于 2014-02-22T00:22:34.443 回答
0

在没有看到您的应用程序中的所有内容是如何设计的情况下,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();
}
于 2014-02-22T01:03:01.967 回答