Noo*_*z42 5 java singleton unit-testing design-patterns
我有时需要只在应用程序生命周期中实例化一次的类.让他们成为单身人士是不好的,因为单元测试变得有问题.
但是,因为在我的应用程序的生命周期中应该有这样的对象的唯一实例,所以在应用程序运行时将这样的对象实例化两次是错误的.
因此,我希望我的应用程序在其生命周期中检测到这样的对象被实例化两次,同时仍然允许在单元测试时对这样的对象进行多次实例化时抛出异常.
我认为这不是一个不合理的要求:如果在应用程序的一个生命周期中只应创建一个这样的对象,那么抛出异常似乎是正确的事情.
这是我正在做的事情:
/**
* The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
* "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
* document are to be interpreted as described in RFC 2119.
*
* You MUST NOT instantiate this class more than once during the application's
* lifecycle. If you try to do so, an exception SHALL be thrown.
*
* You SHOULD be able to instantiate this class more than once when unit
* testing.
*
*
*/
public class LifeCycle {
private static final AtomicInteger cnt = new AtomicInteger( 0 );
@NotNull
public static LifeCycle getNewLifeCycle() {
if ( cnt.incrementAndGet() > 1 && App.isRealApp() ) {
throw new IllegalStateException("Class is already instantiated");
}
return new LifeCycle();
}
}
Run Code Online (Sandbox Code Playgroud)
其中App.isRealApp()在我进行单元测试时总是返回false,并且在真实应用程序运行时始终为true.
我的问题很简单:它是否有意义,我应该如何实现这一点?
如果你的设计需要单身,那么你最好选择单身而不是尝试复杂的东西.
例如,如果您在单元测试单例中遇到的问题是获取模拟实例,那么我将创建一个可实例化的轻量级代理,它提供与您的单例相同的接口.
代理应该没有逻辑 - 它应该只是将调用映射到单例.
然后,您可以在测试中使用它,并使代码库保持单一完整.轻量级代理仍然是测试套件的一部分,而不是发布.
一种解决方案是使用像Spring这样的依赖注入框架.
应用程序配置将指定单例实例,但您的测试用例仍然可以创建按需实例并手动注入它们.
有关更多信息,请访问:http://static.springsource.org/spring/docs/2.5.x/reference/testing.html
另一种方法是,如果您已经在代码中添加了静态单例引用,则将Singleton.getInstance()方法转换为真正的工厂,使用系统属性来控制其行为.这个系统属性可以像一个标志一样简单,表示测试正在进行中,或者与另一个用作真实工厂的类的名称一样复杂(类似于JDK所做的那样DocumentBuilderFactory).