2

我通过构造函数注入使用 IoC 容器而不是 DI。有些人可能会问为什么我使用 IoC 容器而不是构造函数注入。出于此处所述的原因:为什么我需要一个 IoC 容器而不是简单的 DI 代码?. 但是,我发现为我的服务创建单元测试很困难。我不确定如何在运行时模拟我的服务使用的存储库,因为我没有使用构造函数注入(一个难题)。任何人有任何解决方案?

例如:

public class SomeService
{
    private ISomeServiceRepository someServiceRepository;

    public GetSomeThing()
    {
        //how do I mock this repository in my unit test
        someServiceRepository = IoC.Resolve<ISomeServiceRepository>();

        someData = someServiceRepository.getData();

        someOtherService = new SomeOtherService();
        someThing = someOtherService.GetSomeThing();

        return FigureOutSomeThingElse(someData, someThing);
    }

    public FigureOutSomeThingElse(someData, someThing)
    {
        //do some figuring
        return somethingElse;
    }
} 

public class SomeOtherService
{
    private ISomeServiceRepository someOtherServiceRepository;

    public GetSomeThing()
    {
        //how do I mock this repository in my unit test
        someOtherServiceRepository = IoC.Resolve<ISomeOtherServiceRepository>();

        var someData = someOtherServiceRepository.getData();
        return someData;
    }
}
4

3 回答 3

2

人们可以根据需要轻松地发起关于“你做错了”的批评,但我经历过旧代码库无法无私地理解 register-resolve-release 模式的痛苦。但是,我建议不要使用静态容器引用(如 中IoC.)并尝试使容器本身至少注入。

在这种情况下,您只需提供 IoC 注册容器的测试版本,但您可以编写测试配置而不是正常的应用程序配置。

这不会是任何真正意义上的嘲弄或存根,事实上这些术语可能会使解决方案相当混乱。

本质上,在单元测试中它只是一个不同的活动配置。您仍然必须手动注册类型,如果当前配置代码位于单元测试的执行路径中,您可能难以禁用当前配置代码。

我们有一个容器,可以根据需要在 IoC 模式中解析(用于少数类型),并且为了测试,我们只需创建一个新容器(基本上,一个用于代码配置,另一个用于单元测试)。我们的用例略有不同,因为我们将容器注入到类中,而不是像您的情况那样具有静态可访问类型。

于 2012-07-11T13:54:43.307 回答
2

你真的不应该在你的类方法中使用 IOC.Resolve 。无论如何,它非常接近于new编写您的代码,这是您试图避免使用 DI 的一部分。一种更好、更可测试的编写方式是这样的。

Public Class SomeService
{

  ISomeServiceRepository someServiceRepository;

  public SomeService(ISomeServiceRepository someServiceRepository)
  {
    this.someServiceRepository = someServiceRepository
  }

  Public GetSomeThing()
  {

    someData = someServiceRepository.getData();
    ...
  }
}

通过这样做,您可以模拟您的界面并直接注入它。

如果你必须使用.Resolve,那么亚当的方法是你能做的最好的

于 2012-07-11T13:58:22.010 回答
0

我明白了,这就是我所做的......

(我正在使用 Unity.Net 和 RhinoMock)

  • 创建了一个实现 IContainerAccessor 的 baseUnitTest 类

  • 在构造函数中创建并初始化 UnityContainer 的新实例

  • 创建了实现 IContainerAccessor.Container 的“UnityContainer”只读公共属性

  • 创建了一个继承 baseUnitTest 的单元测试类

  • 在测试方法中添加了以下代码...

    Mocker = 新 Rhino.Mocks.MockRepository()

    SomeRepository = Mocker.DynamicMock(Of ISomeRepository)()

    MyBase.UnityContainer.RegisterInstance(Of ISomeRepository)(SomeRepository)

    Rhino.Mocks.Expect.Call(Of SomeResult)(SomeRepository.SomeMethod("someArg")).Return(New SomeResult())

    Mocker.ReplayAll()

    someService = 新的 SomeService()

    '此方法使用 IOC.Resolve(ISomeRepository) 并调用 SomeRepository.SomeMethod someResult = someService.someMethod()

    Assert.IsNotNull(someResult)

  • 完毕

于 2012-07-17T14:39:58.637 回答