如何使用Moles测试虚拟方法?

时间:2011-11-29 05:55:35

标签: c# unit-testing moles

如何使用Moles测试IsHappy函数?

class SomeClass
{
     protected virtual bool IsHappy(string mood)
     {
          return (mood == "Happy");
     }
}

我尝试使用Stub来测试是否

SSomeClass stub = new SSomeClass();
stub.CallBase = true;
Assert.IsTrue(stub.IsHappyString("Happy"));

...但IsHappyString方法返回null,因此抛出NullReference异常。

那么,我该如何测试IsHappy方法的默认实现?

2 个答案:

答案 0 :(得分:2)

我在这里忘记了存根。 Stubs / mocks用于伪造依赖项的行为。如果您想要测试SomeClassClient并且使用了SomeClass,那么你可以存储你的SomeClass:

    public class Foo
    {
        public virtual int GetFoosInt()
        {
            return 12;
        }
    }
    public class FooClient
    {
        private Foo _foo;

        public FooClient(Foo foo)
        {
            _foo = foo;
        }

        public int AddOneToFoosInt()
        {
            return _foo.GetFoosInt() + 1;
        }
    }

在这个例子中,当测试FooClient时,你要测试的是它返回的不仅仅是“GetFoosInt()”。您实际上并不关心FoosInt用于测试FooClient的内容。因此,您可以创建一个Foo存根,您可以在其中设置GetFoosInt以返回您想要的任何内容。

在您的情况下,测试受保护的虚拟成员,我会选择:

[TestClass]
public class SomeClassTest
{
    private class DummySomeClass : SomeClass
    {
        public bool IsHappyWrapper(string mood)
        {
            return IsHappy(mood);
        }
    }

    [TestMethod]
    public void SomeTest()
    {
        var myClass = new DummySomeClass();

        Assert.IsTrue(myClass.IsHappyWrapper("Happy"));
    }
}

这使您可以“直接”访问受保护的虚拟测试默认行为。唯一需要注意的是,如果你开始定义抽象成员并一般地添加到SomeClass,你也必须将它们添加到这个虚拟继承者中,增加测试维护开销。

我的纯粹主义者说你应该让受保护的成员独自离开,只通过公共界面测试它们。但是,在你的情况下,这可能是也可能不实际,我认为这种方法没有任何损害。

答案 1 :(得分:1)

Stubs和Moles用于将类与其具有的任何依赖项隔离,无论是环境依赖还是类依赖。这个类没有任何依赖关系,那你为什么要试图mole或stub?

如果要在人们覆盖它时确保此基类正常工作,那么您需要创建一个测试实现。在这种情况下,这或多或少是您的测试用例的样子:

public SomeClassTestAdapter : SomeClass
{
    public bool GetIsHappy(string mood)
    {
        return IsHappy(mood);
    }
}

[Test]
public void ShouldReturnTrueWhenPassedHappy()
{
    var classUnderTest = new SomeClassTestAdapter();
    bool result = classUnderTest.IsHappy("Happy");
    Assert.IsTrue(result, "Expected result to be true");
}

[Test]
public void ShouldReturnFalseWhenPassedLowerCaseHappy()
{
    var classUnderTest = new SomeClassTestAdapter();
    bool result = classUnderTest.IsHappy("happy");
    Assert.IsFalse(result, "Expected result to be false");
}

[Test]
public void ShouldReturnFalseWhenPassedNull()
{
    var classUnderTest = new SomeClassTestAdapter();
    bool result = classUnderTest.IsHappy(null);
    Assert.IsFalse(result, "Expected result to be false");
}

此代码中没有地方应该挤入存根或痣。

如果您不想为此案例创建适配器类,则可以使用内置的.Net功能,而不是像Moles这样的大型付费依赖项。通过思考和动态,您可以访问受保护或私有成员。见这个例子: