【问题标题】:Dependency Injection, Unit Testing, and Information Hiding [closed]依赖注入、单元测试和信息隐藏
【发布时间】:2011-01-17 01:22:53
【问题描述】:

假设你有一个类 Foo,它的私有成员类型为 Bar。您不希望用户知道 Foo 的实现包含一个 Bar,并且您不希望用户能够创建自己的 Bar 并通过 Foo 的构造函数、任何其他方法或配置文件传递它。

编辑:Bar 也存在问题,因为它会访问测试环境无法控制的资源,例如特殊数据库、网络连接或其他进程。

当您还希望能够对 Foo 进行单元测试时,您会怎么做?依赖注入仍然可能吗?这是否意味着 Bar 和 Foo 过于紧密耦合(即使依赖是一种方式)并且这种情况永远不可接受?

【问题讨论】:

    标签: unit-testing dependency-injection information-hiding


    【解决方案1】:

    如果你能提供帮助,你永远不想隐藏依赖关系。

    如果是你的代码,你应该通过重新设计 Bar 来明确依赖关系,以接受昂贵资源产生的对象,而不是直接访问昂贵的资源:将数据库访问代码(或任何它是)移出 @ 987654323@ 和 Foo,您可以在其中注入测试替身。

    如果这不切实际(即,你正在处理别人的课程),Dror's list 非常好。

    【讨论】:

    • +1:设计(完全隐藏的 Bar)是个坏主意。
    【解决方案2】:

    [免责声明:我在Typemock工作]

    你有三个选择:

    1. 创建一个设置 Bar 类的内部方法 - 在 assemblyInf.cs 文件中使用 InternalVisibleTo,您可以让您的测试设置该类。
    2. 使用 DI 注入 Bar 类,在测试期间用 dummy 或 fake 更改该类。
    3. 使用诸如 Typemock Isolator (.NET) 之类的 Faking/Mocking 框架,使您能够对使用 Isolate.Swap.NextInstance<Bar>.With(fakeBar); 在另一个类中创建的对象设置虚假行为

    【讨论】:

    • +1 表示内部方法的想法。不幸的是,并非所有语言都支持内部方法,例如 java。我想不出一种方法来完成依赖注入..也许通过适配器设计模式?你能举个例子吗?
    • 原来在java的包级别有内部访问,所以我错了。
    • 另外,您可以将构造函数设为内部(同样,在 .NET 中使用 InternalsVisibleToAttribute)并提供公共工厂。除非我正在设计一个带有安全问题的面向公众的 API,否则我不会打扰。 @insipid - 你使用什么语言?
    • 目前是java,但这个问题可能发生在我身上,用任何语言:)
    • 接受答案,但如果有人决定提供一些依赖注入示例(没有构造函数或配置文件),我将不胜感激。
    【解决方案3】:

    如果 Bar 类型只是 Foo 的一个实现细节,那么您的单元测试永远不必担心创建 Bars,因为它们应该只使用 Foo 的公共接口。

    编辑:如果 Bar 访问外部资源,那么我会将其设置为 Foo 的显式依赖项,然后需要将一个实例传递给 Foo 的构造函数,然后可以轻松地对其进行模拟以进行单元测试。

    【讨论】:

    • 好点,我的问题太模糊(编辑)
    • 如果 Bar 访问互联网或数据库会发生什么 - 你仍然需要伪造/模拟/存根它
    • +1:如果 Bar 完全隐藏,它就不是真正可测试的,是吗?如果它具有外部依赖项,则不应隐藏它。任何隐藏 Bar 的尝试都是糟糕的设计。
    【解决方案4】:

    您的问题不在于您需要访问私人成员。这只是所讨论的类不是被设计为孤立的这一事实的一个症状。它只允许一种非常特定的用法,即new 向上一个对象,该对象将使用昂贵的资源。

    即使您成功破解了不可测试的设计,您仍然只会进行集成测试。单元测试是关于隔离的,这与集成相反。由于该类不能被隔离,根据定义,您不能对其进行单元测试。

    是否有理由将依赖项外部化是不可取的?这个对象如何使它免于像其他对象一样被依赖注入?

    编辑

    我当然意识到你可以用一些诡计来隔离它。然而,这些技术绕过了公共接口,限制了未来的灵活性并增加了有人破坏它的可能性(基本上,使私有成员的用处无效)。

    【讨论】:

    • +1:隐藏栏是个坏主意。
    猜你喜欢
    • 2018-03-03
    • 2021-06-19
    • 1970-01-01
    • 2017-11-03
    • 2016-02-16
    • 2010-10-23
    • 2017-04-01
    相关资源
    最近更新 更多