我的建议是重新设计你的Configuration
课程。因为你的问题本质上是理论上的,有一点实际的方面(单元测试失败),我会提供一些链接来支持我的想法。
首先,创建Configuration
一个非静态类。谷歌工程师 Miško Hevery 就面向可测试性的 OO 设计做了一个非常好的演讲,他特别提到全局状态是一个糟糕的设计选择,特别是如果你想测试它。
您的配置可以通过构造函数接受RegistryProvider
实例(我假设您听说过依赖注入原则)。RegistryProvider
责任只是从注册表中读取值,这是它应该做的唯一事情。现在,当您测试时Configuration
,您将提供RegistryProvider stub
(如果您不知道存根和模拟是什么 - 谷歌它,它们本质上很简单),您将在其中硬编码特定注册表项的值。
现在,好处:
- 你很好
unit tests
,因为你不依赖注册表
- 你没有全局状态(可测试性)
- 您的测试不相互依赖(每个都有单独的
Configuration
实例)
- 您的测试不依赖于执行它们的环境(您可能没有访问注册表的权限,但您仍然可以测试您的
Configuration
课程)
如果你觉得你不太擅长依赖注入,我会推荐一个了不起的艺术和工程,由马克西曼的天才提供给凡人的灵魂,称为.NET 中的依赖注入。我读过的关于类设计的最好的书之一,它面向 .NET 开发人员。
为了让我的回答更具体:
我应该使用反射来为每个测试重新构建类吗?
不,你不应该在你的测试中使用反射(只有在没有其他情况的情况下)。反思将使您进行测试:
使用面向对象的实践结合封装实现隐藏实现。然后只测试外部行为,不要依赖内部实现细节。这将使您的测试仅依赖于外部行为而不依赖于内部实现,这可能会发生很大变化。
我应该重新设计这个类来检查属性而不是构造函数中的注册表吗?
如我的回答中所述设计您的课程将使您能够测试您的课程而不访问注册表。这是单元测试的基石——不要依赖外部系统(数据库、文件系统、Web、注册表等)。如果您想测试是否可以访问注册表 - 编写单独的集成测试,您将在其中写入注册表并从中读取。
现在我没有足够的信息来告诉你是应该通过构造函数读取注册表RegistryProvider
,Configuration
还是按需懒惰地读取注册表,这是一个棘手的问题。但我绝对可以说 - 尽量避免全局状态,尽量减少对测试中实现细节的依赖(这与整个 OO 原则有关)并尝试单独测试对象,即不访问外部系统。然后你可以模仿特殊情况,例如当注册表不可用时,你的类行为是否符合预期?如果您通过类的静态成员直接访问注册表,则很难重新创建这样的场景Configuration
。