单例和单元测试
2022-08-31 20:12:20
Effective Java在单元测试单例上有以下声明
使类成为单例可能会使测试其客户端变得困难,因为除非它实现作为其类型的接口,否则不可能用模拟实现代替单例。
谁能解释为什么会这样?
Effective Java在单元测试单例上有以下声明
使类成为单例可能会使测试其客户端变得困难,因为除非它实现作为其类型的接口,否则不可能用模拟实现代替单例。
谁能解释为什么会这样?
您可以使用反射来重置单例对象,以防止测试相互影响。
@Before
public void resetSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field instance = MySingleton.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, null);
}
参考:单元测试单例
问题不在于测试单例本身;这本书说,如果你试图测试的一个类依赖于一个单例,那么你很可能会遇到问题。
除非您 (1) 使单例实现一个接口,并且 (2) 使用该接口将单例注入到您的类中。
例如,单例通常直接实例化,如下所示:
public class MyClass
{
private MySingleton __s = MySingleton.getInstance() ;
...
}
MyClass
现在可能很难自动测试。例如,正如@Boris Pavlović 在他的回答中指出的那样,如果单例的行为基于系统时间,那么您的测试现在也依赖于系统时间,并且您可能无法测试依赖于星期几的用例。
但是,如果您的单例“实现了作为其类型的接口”,那么您仍然可以使用该接口的单例实现,只要您将其传入:
public class SomeSingleton
implements SomeInterface
{
...
}
public class MyClass
{
private SomeInterface __s ;
public MyClass( SomeInterface s )
{
__s = s ;
}
...
}
...
MyClass m = new MyClass( SomeSingleton.getInstance() ) ;
从测试的角度来看,你现在并不关心是否是单例:你也可以传递你想要的任何其他实现,包括单例实现,但最有可能的是,你会使用某种你从测试中控制的模拟。MyClass
SomeSingleton
顺便说一句,这不是这样做的方法:
public class MyClass
{
private SomeInterface __s = SomeSingleton.getInstance() ;
public MyClass()
{
}
...
}
这在运行时仍然相同,但是对于测试,您现在再次依赖于 。SomeSingleton