【问题标题】:Dependency Injection resolve and unit testing依赖注入解析和单元测试
【发布时间】:2010-10-23 15:15:43
【问题描述】:

我正在尝试学习依赖注入,但在对应用程序进行单元测试时遇到了问题。

我正在编写一个控制台应用程序,容器是在 Main() 中创建和初始化的,它在 Program.Container 中以 get-property 的形式提供,所以我可以在我的应用程序的任何地方调用 Program.Container.Resolve<..>()

我有一个这样的 ServiceValidator 类:

public class ServiceValidator
{
    private readonly IConfiguration _configuration;
    private readonly IService _service;

    public ServiceValidator(IConfiguration configuration, IService service)
    {
        _configuration = configuration;
        _service = service;
    }

在我使用的另一个类中

ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>();
serviceValidator.VerifyVersion();

是对Program.Container.Resolve 的调用导致我在单元测试中出现问题,因为它尚未设置。

在容器上调用 resolve 是一种不好的做法吗?我可以在 Main() 中创建 ServiceValidator 实例并传递对象,但这似乎很愚蠢,因为它会导致对象的大量参数被传递给下一个方法。

所以我想在一个类中调用 Resolve 是可以接受的,但是必须为单元测试配置容器。我应该怎么做,我应该将容器移动到程序类之外的另一个地方吗?你会推荐什么?

如果重要的话,我正在使用 Unity 和 C#

谢谢:-)

【问题讨论】:

    标签: c# .net unit-testing dependency-injection ioc-container


    【解决方案1】:

    在容器上调用 resolve 是一种不好的做法吗?我可以在 Main() 中创建 ServiceValidator 实例并传递对象,但这似乎很愚蠢,因为它会导致刚刚传递给下一个方法的对象有很多参数。

    当您一直使用依赖注入时,您将不需要向对象传递大量参数。每个对象的构造函数应该只将那些它自己直接使用的依赖作为参数——它不会知道其直接依赖的传递依赖。

    因此,如果您有一个需要 ServiceValidator 的类 X,那么类 X 将有一个 ServiceValidator 类型的构造函数参数。那么如果某个类 Y 使用类 X,那么类 Y 将有一个类型为 X 的构造函数参数。请注意,Y 对 ServiceValidator 一无所知,因此您不需要将 ServiceValidator 从一个类传递给另一个 - 唯一使用它的地方是在构建 X 时,这通常由 DI 框架完成,或者仅在手写工厂中的一个地方完成。

    更多信息的链接:

    【讨论】:

    • >当你一直使用依赖注入时,>那么你就不需要向对象传递很多参数了。我从来没有考虑过为所有课程做 DI。我只是想为使用外部东西的类做 DI,比如 Web 服务、数据库,也许还有配置。如果我理解你是正确的,你永远不会在框架类之外的任何东西上调用 resolve 或 new ?感谢您的回答:-)
    • 开始想到另一件事。这是否意味着所有对象都是预先创建的,在它们可能真正需要之前很长时间,甚至可能根本不需要它们?
    • 一直使用 DI 时,通过从 DI 容器中获取应用程序的根对象来引导应用程序,之后不再直接访问容器。 docs.google.com/Doc?id=dd2fhx4z_5df5hw8#xefn 当创建一些将它们作为依赖项的对象时,将创建这些对象。通常,具有相同生命周期范围的所有对象都会同时实例化。如果某些对象具有不同的生命周期范围,那么您可以注入工厂以在正确的时间实例化它们。
    【解决方案2】:

    我通常允许在 main 等位置调用来解决来自容器的依赖关系,尽管我仍然尝试将它们保持在最低限度。然后我要做的是在测试类的初始化方法中配置容器。对于需要调用容器的任何测试类,我都使用假实现对其进行了初始化。

    不调用任何需要初始化容器的测试类然后能够忽略它并且不使用假货。我通常在这些情况下使用模拟。

    我还使用了Microsoft Service Locator,因此我所采用的依赖关系来自 .NET Framework,而不是特定容器。这让我可以在路上使用任何我想要的东西,甚至是自制的容器。

    【讨论】:

    • 我仍然希望看到一个很好的模式来解决这个问题而不依赖于 Program 类...
    • >我一直这样打电话.. 你的意思是“解决”对容器的调用吗?
    【解决方案3】:

    您可以使用静态类作为容器的初始化程序。像 BootStrapper.cs 这样的东西就可以了。然后,您可以在代码和测试中引用类方法。

    【讨论】:

      【解决方案4】:

      嗯,从技术上讲,您所做的是您班级中的服务地点。

      我记得不久前读过这篇文章:

      http://martinfowler.com/articles/injection.html

      对于我的课程,我从不尝试在其中使用 Resolve。我在需要时通过容器创建对象。对于单元测试,我要么使用一些模拟库和存根类。

      【讨论】:

        【解决方案5】:

        问题在于您正在尝试测试 Main 方法。这种方法几乎不可能进行单元测试。

        我认为最好不要对 Main 方法进行单元测试,因为:

        • 现代单元测试的重点在于设计
        • 您应该尽量减少单元测试中对配置的依赖。可以使用冒烟测试或集成测试来测试配置。

        【讨论】:

        • 不,我不尝试测试 Main 方法。
        猜你喜欢
        • 2018-03-03
        • 2021-06-19
        • 1970-01-01
        • 2017-11-03
        • 1970-01-01
        • 2016-02-16
        • 2017-04-01
        相关资源
        最近更新 更多