我有一个Singleton,可以通过这样的静态属性在我的课程中访问:OtherClassNotBeingTested.Instance.SomeInstanceMethod()
我想测试我的课程,而不是制作其中一个对象。当调用静态属性Instance
的getter时,有没有办法让RhinoMocks返回存根?
更清楚一点,这是Instance属性的代码:
/// <summary>
/// Make a property to allow the OtherClassNotBeingTested class
/// to be a singleton
/// </summary>
public static OtherClassNotBeingTested Instance
{
get
{
// Check that the instance is null
// NOTE: COMMENTS BELOW HAVE SHOWN THIS TO BE BAD CODE. DO NOT COPY
if (mInstance == null)
{
// Lock the object
lock (mSyncRoot)
{
// Check to make sure its null
if (mInstance == null)
{
mInstance = new OtherClassNotBeingTested();
}
}
}
// Return the non-null instance of Singleton
return mInstance;
}
}
更新: 这就是我最终修复它的方法:
class ClassBeingTested
{
public ClassBeingTested(IGuiInterface iGui):this(iGui, Control.Instance)
{
}
public ClassBeingTested(IGuiInterface iGui, IControl control)
{
mControl = control;
//Real Constructor here
}
}
我的单元测试调用第二个构造函数。实际代码调用第一个构造函数。该类中的代码使用本地字段 mControl 而不是单例。 (我认为这称为依赖注入。)
我还根据
Tony the Pony 的建议重构了Singleton。
答案 0 :(得分:4)
我希望您的mInstance
变量声明为volatile,否则您的DCL实现会被破坏。说真的,你真的需要那种程度的懒惰吗?我个人推荐一些simpler patterns available。
然而,当涉及到模拟 - 不,你不能用RhinoMocks模拟静态调用。有一些工具允许这样做,例如Typemock,但我个人认为应用程序首先会重新测试它。
另一种选择是拥有一个“作弊”单例,您可以在其中设置测试用例中单例属性的值。如果你让属性返回一个接口而不是单例类本身,你可以用一个模拟替换真正的单例。
答案 1 :(得分:4)
尽管有其他谣言你可以嘲笑单身人士,但请看我的回答:
How to Mock a Static Singleton?
在这种情况下,它甚至更简单,因为没有静态构造函数。如果您的单例已经实现了一个接口,则无需更改生产代码。