2010-01-30 34 views
17

我有一个能够成功通过测试的独立单例。但是,一组测试会失败,因为一旦定义了单例,它不允许重置实例。使用JUnit测试的不同单例实例

有关如何解决这个问题的任何想法?

回答

9

请勿使用单身人士。

具体而言,单例和全局变量之间的唯一区别是,单例尝试强制执行单个实例(例如,通过使构造函数成为私有的)。

而是使构造函数公开并使用新实例编写测试。在您的实际程序中,使用getInstance()获取规范全局实例(或使用IOC容器)。并且请记住singletons are pathological liars

如果你仍然对单例的想法感到太舒服,而不是公开构造函数,你可以添加一个公共(和静态)工厂方法来创建实例,例如:

public static MyClass TEST_CreateInstance() { 
    return new MyClass(); 
} 
3

您可以添加一个方法来销毁单例,例如destroyMe();您可以在其中取消初始化所有内容并将单例的实例设置为null。

public void destroyMe(){ 
    this.instance = null; 
    //-- other stuff to turn it off. 
} 

我会离开的同步问题,虽然;)

但是,为什么你需要重新初始化单为每个测试?它不应该基于单例的概念而有所不同。

10

我假设你在单例类中有一个私有静态字段来存储初始化的实例。

如果你不想修改你的代码,你可以定义一个在每次测试之后运行的拆卸方法,并且在这个方法中你通过反射设置这个静态字段为空,如here

+1

-1,国际海事组织这是一个糟糕的情况更糟糕 – orip 2010-02-01 21:11:33

+13

+1为实际的解决方案。我无法控制第三方代码,这是一个单身人士,需要解决方案,而不是建议如何完成。 – eis 2013-08-14 07:01:11

1

一般提防单身人士,通常他们是邪恶的,糟糕的设计,并倾向于代表大的易变全局变量(这对维护不利)。

仍然得到到位的测试首先,你可以这样做:

 

static setInstance(...){ //package visibility or in difficult cases you have to use public 
    instance = ...; 
} 
 

如说这更是一个解决办法。所以得到第一个测试的地方,但然后重新从单身模式。

0

单身实例需要通过测试本身传递给SUT--这样你可以为每个测试创建单身(并且销毁)。采用IoC和嘲笑框架,如Mockito,将使这种方法几乎微不足道。

1

高度推荐移动从单身远离作为设计图案,并用单例为范围(依赖注入)。这只会让你的问题消失。但是,假设你被困在单身人士的世界里,那么你有几个选择取决于你是在测试单身人士还是依赖关系。

如果您正在测试依赖项目,那么您可以使用PowerMockJMockIt模拟单例。请参阅我的previous post关于嘲弄Runtime.getRuntime以获取有关如何解决此问题的说明。

如果您正在测试Singleton,那么您需要放松构建规则,或给Singleton一个“重置”方法。

1

Spring为这个特殊用例提供了DirtiesContext注释,其中您需要每个测试用例的单例bean的新实例。它基本上为每个应用了该注释的testcase/testclass创建一个新的应用程序上下文。