假设您有一个类 Foo,其私有成员类型为 Bar。您不希望用户知道 Foo 的实现包含一个 Bar,并且您不希望用户能够创建自己的 Bar 并通过 Foo 的构造函数、任何其他方法或配置文件传递它。
编辑: Bar 也存在问题,因为它访问测试环境无法控制的资源,例如特殊数据库、网络连接或其他进程。
当您还希望能够对 Foo 进行单元测试时,您会怎么做?依赖注入仍然可能吗?这是否意味着 Bar 和 Foo 过于紧密耦合(即使依赖是一种方式)并且这种情况永远不可接受?
假设您有一个类 Foo,其私有成员类型为 Bar。您不希望用户知道 Foo 的实现包含一个 Bar,并且您不希望用户能够创建自己的 Bar 并通过 Foo 的构造函数、任何其他方法或配置文件传递它。
编辑: Bar 也存在问题,因为它访问测试环境无法控制的资源,例如特殊数据库、网络连接或其他进程。
当您还希望能够对 Foo 进行单元测试时,您会怎么做?依赖注入仍然可能吗?这是否意味着 Bar 和 Foo 过于紧密耦合(即使依赖是一种方式)并且这种情况永远不可接受?
如果你能提供帮助,你永远不想隐藏依赖关系。
如果它是您的代码,您应该通过重新设计来明确依赖关系Bar
以接受昂贵资源产生的对象,而不是直接访问昂贵的资源:将数据库访问代码(或任何它是)移出Bar
和移入Foo
您可以注入的地方测试双打。
如果这不切实际(即,您正在处理其他人的课程),Dror 的列表非常好。
[免责声明:我在Typemock工作]
你有三个选择:
Isolate.Swap.NextInstance<Bar>.With(fakeBar);
如果 Bar 类型只是 Foo 的一个实现细节,那么您的单元测试永远不需要担心创建 Bars,因为它们应该只使用 Foo 的公共接口。
编辑:如果 Bar 访问外部资源,那么我会将其设为 Foo 的显式依赖项,然后需要将一个实例传递给 Foo 的构造函数,然后可以轻松地对其进行模拟以进行单元测试。
您的问题不在于您需要访问私人成员。这只是所讨论的班级并非被设计为孤立的事实的一个症状。它只允许一种非常特定的用途,即new
启动一个需要昂贵资源的对象。
即使您成功破解了不可测试的设计,您仍然只会进行集成测试。单元测试是关于隔离的,这与集成相反。由于该类不能被隔离,根据定义,您不能对其进行单元测试。
是否有理由将依赖关系外部化?这个对象怎么样使它免于像其他对象一样被依赖注入?
编辑:
我当然意识到你可以用一些诡计来隔离它。然而,这些技术绕过了公共接口,限制了未来的灵活性并增加了有人破坏它的可能性(基本上,使私有成员的用处无效)。