我有一个包含统计信息对象引用的单例。
当我在使用该单例的程序上运行一些单元测试时,这些值会在测试之间保留。
我认为当我执行Program.Main()时,在单元测试之间都会重新开始,但不知何故它记住了上次测试的结果。
我如何编写能够相互隔离的单元测试(我不想使用clean()函数——我希望它能够以新的"一切"重新开始)?
我有一个包含统计信息对象引用的单例。
当我在使用该单例的程序上运行一些单元测试时,这些值会在测试之间保留。
我认为当我执行Program.Main()时,在单元测试之间都会重新开始,但不知何故它记住了上次测试的结果。
我如何编写能够相互隔离的单元测试(我不想使用clean()函数——我希望它能够以新的"一切"重新开始)?
简洁版:不要将单例写成单例。将它们编写为普通类,并通过控制反转容器调用它们,其中您已将该类配置为单例。
这样,您可以完全进行单元测试,如果您决定今天或明天单例不是该类的正确生命周期,则只需修改IoC容器的配置即可。
AppDomain
很困难。例如,NUnit会为每个测试会话(通过所有选择的测试的一次遍历)创建一个新的AppDomain
。然后,NUnit必须将其代码注入该AppDomain
以运行测试。这不是易事。您不能只是创建一个新的AppDomain
并期望在其中自动运行。您必须让您的代码在其中运行。总体而言,此答案可能有可能性,但我不同意“这不应该太难”的部分。 - Mike Two当试图测试单例本身时,以下可能是一种解决方案:
public class Singleton
{
private static Singleton _Instance;
public static Singleton getInstance() {
if (_Instance == null)
{
_Instance = new Singleton();
}
return _Instance;
}
private Singleton()
{
}
public static resetForTesting() {
_Instance = null
}
}
因此,在您的单元测试框架中,您将在每个单元测试之前调用Singleton.resetForTesting()
。
注意:这种方法的缺点是,没有代码级别的限制可以阻止某人在生产代码中调用此方法,即使它只应该与测试代码一起使用。因此,您必须依靠文档来传达这一点给其他人。
你可以为单例类添加属性设置器,以重新分配单例实例。这样,在测试中,你就可以对单例进行存根/模拟。