如何使用moq来测试调用受保护助手的代码

时间:2011-10-21 15:28:10

标签: c# unit-testing moq

我目前正在运行如下所示的测试:

// In Blah.cs
public class ClassUnderTest

{

    public bool MethodUnderTest()

    {

        // Do a bunch of stuff...

        return HelperMethod();

    }



    protected virtual bool HelperMethod()

    {

        bool success = false;

        // Proprietary Hardware Access.

        // Database Calls.

        // File System Modifications.

        return success;

    }

}


// In TestBlah.cs

public class TestStub : ClassUnderTest

{

    public bool HelperMethodReturnValue;



    protected override bool HelperMethod()

    {

        return HelperMethodReturnValue;

    }

}



[TestClass]

public class TestingClass

{

    [TestMethod]

    public void ClassUnderTest_MethodUnderTest_TestHelperReturnsTrue()

    {

        var stub = new TestStub();

        stub.HelperMethodReturnValue = true;

        Assert.IsTrue(stub.MethodUnderTest());

    }



    [TestMethod]

    public void ClassUnderTest_MethodUnderTest_TestHelperReturnsFalse()

    {

        var stub = new TestStub();

        stub.HelperMethodReturnValue = false;

        Assert.IsFalse(stub.MethodUnderTest());

    }

}

以上内容对于简单的事情看起来很好,但是存根类会快速地呈指数级增长和更复杂。 我想用Moq替换存根类。但是这不会编译,因为由于某种原因我无法在受保护的方法上设置返回值。

[TestMethod]

public void ClassUnderTest_MethodUnderTest_TestHelperReturnsFalse()

{

    var mockClass = new Mock<ClassUnderTest>();
    mockClass.Protected().Setup("HelperMethod").Returns(false);

    Assert.IsFalse(mockClass.Object.MethodUnderTest());

}

任何人都知道我该怎么做?我可以用moq做这个吗?

2 个答案:

答案 0 :(得分:25)

查看moq source code猜测,您需要显式调用安装程序的通用版本。非泛型版似乎用于void方法。所以试试

mockClass.Protected().Setup<bool>("HelperMethod").Returns(false);

除此之外,我建议重新思考你的课堂设计。如果HelperMethod()正在做这么多事情,那么将自己的类作为依赖注入ClassUnderTest是值得的。测试模拟对象,而不是使用模拟对象来测试“真实”的东西,而不是模拟框架的制作(至少在第一时间)。

答案 1 :(得分:4)

受保护的方法不是隔离依赖项的好方法,但有时会出现这种情况,特别是在调整遗留代码以实现可测试性时。避免基于字符串的笨拙Moq语法的一个选项是使方法“受保护内部”(或者如果您不打算在正常情况下从其他程序集中覆盖它,则只是“内部”。)然后在程序集上使用InternalsVisibleTo揭露方法。这有点像黑客攻击,但为此目的使用受保护的方法已经是一个黑客攻击了。在某些方面,我更喜欢“内部”方法,因为它清楚地表明这是一个你不应该使用的后门方法(测试除外),而不是你可能希望在正常情况下覆盖的受保护方法的使用。