use*_*248 5 c# nunit unit-testing static-constructor
我有一个静态Configuration类负责整个系统的数据设置.它在构造函数中从注册表加载某些值,并且它的所有方法都基于这些值.如果它无法从注册表中获取值(如果应用程序尚未激活,则可能),它会抛出一个异常,转换为a TypeInitializationException,这对我很好.
我使用NUnit编写了单元测试,以确保Configuration的构造函数正确处理所有情况 - 正常值,空值,空值.每个测试使用相关值初始化注册表,然后在Configuration中调用一些方法.这就是问题所在:NUnit决定先运行Null测试.它清除注册表,初始化Configuration,抛出异常 - 一切都很好.但是,因为这是一个静态类,其构造函数只是失败了 - 它不会为其他测试重新构造类,它们都会失败.
即使没有Null测试,我也会遇到问题,因为对于所有使用它的类,配置可能(我猜)会被初始化一次.
我的问题是:我应该使用反射为每个测试重新构造类,还是应该重新设计此类以检查属性中的注册表而不是构造函数?
Ily*_*nov 10
我的建议是重新设计你的Configuration课程.因为你的问题本质上是理论性的,有一点实际意义(单元测试失败),我会提供一些链接来支持我的想法.
首先,创建Configuration一个非静态类.谷歌的工程师MiškoHevery在OO可测性设计方面发表了非常好的演讲,他特意将全球状态作为一个糟糕的设计选择,特别是如果你想测试它.
您的配置可以RegistryProvider通过构造函数接受实例(我假设您已经了解了依赖注入原则).RegistryProvider责任只是从注册表中读取值,这是它应该做的唯一事情.现在,当您进行测试时Configuration,您将提供RegistryProvider stub(如果您不知道什么是存根和模拟 - 谷歌它们,它们本质上是简单的),您将在其中硬编码特定注册表项的值.
现在,好处:
unit tests,因为你不依赖注册表Configuration实例)Configuration类)如果您觉得自己并不擅长依赖注入,我会推荐一种奇妙的艺术和工程,由Mark Seemann的天才提供给凡人,称为.NET中的依赖注入.我读过的关于类设计的最好的书之一,面向.NET开发人员.
为了使我的答案更具体:
我应该使用反射来重新构建每个测试的类吗?
不,你不应该在你的测试中使用反射(只有在没有其他情况下).Reflexion会让你测试:
使用面向对象的实践与封装相结合来实现隐藏实现.然后只测试外部行为,不依赖于内部实现细节.这将使您的测试仅依赖于外部行为,而不是内部实现,这可能会发生很大变化.
我应该重新设计这个类来检查属性中的注册表而不是构造函数吗?
按照我的回答中的描述设计你的课程将使你能够测试你的课程根本不访问注册表.这是单元测试的基石 - 不依赖于外部系统(数据库,文件系统,Web,注册表等......).如果您想测试是否可以访问注册表 - 编写单独的集成测试,您将在其中写入注册表并从中读取.
现在我没有足够的信息告诉你是否应该RegistryProvider在Configuration构造函数中读取注册表,或者懒惰地按需读取注册表,这是一个棘手的问题.但我绝对可以说 - 尝试尽可能地避免全局状态,尽量减少对测试中实现细节的依赖(这与整个OO原则有关)并尝试单独测试对象,即无需访问外部系统.然后,您可以模仿特殊情况,例如,当注册表不可用时,您的类是否按预期运行?如果直接通过Configuration类的静态成员访问注册表,则很难重新创建此类场景.