Rhino Mocks - Stub a Singleton

时间:2009-11-02 23:43:05

标签: c# unit-testing mocking rhino-mocks rhino-mocks-3.5

我有一个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。

2 个答案:

答案 0 :(得分:4)

我希望您的mInstance变量声明为volatile,否则您的DCL实现会被破坏。说真的,你真的需要那种程度的懒惰吗?我个人推荐一些simpler patterns available

然而,当涉及到模拟 - 不,你不能用RhinoMocks模拟静态调用。有一些工具允许这样做,例如Typemock,但我个人认为应用程序首先会重新测试它。

另一种选择是拥有一个“作弊”单例,您可以在其中设置测试用例中单例属性的值。如果你让属性返回一个接口而不是单例类本身,你可以用一个模拟替换真正的单例。

答案 1 :(得分:4)

尽管有其他谣言你可以嘲笑单身人士,但请看我的回答:

How to Mock a Static Singleton?

在这种情况下,它甚至更简单,因为没有静态构造函数。如果您的单例已经实现了一个接口,则无需更改生产代码。