3

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

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

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

4

4 回答 4

5

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

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

如果这不切实际(即,您正在处理其他人的课程),Dror 的列表非常好。

于 2010-02-15T16:45:03.223 回答
4

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

你有三个选择:

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

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

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

于 2010-02-15T16:22:04.670 回答
1

您的问题不在于您需要访问私人成员。这只是所讨论的班级并非被设计为孤立的事实的一个症状。它只允许一种非常特定的用途,即new启动一个需要昂贵资源的对象。

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

是否有理由将依赖关系外部化?这个对象怎么样使它免于像其他对象一样被依赖注入?

编辑

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

于 2010-02-15T22:34:07.270 回答