测试使用NUnit调用私有方法的公共方法

Sid*_*ant 4 c# nunit unit-testing nmock private-members

我在一个类中有一个公共方法,该类在内部调用该类中的特定私有方法。看起来像这样:

public class MyClass : IMyClassInterface
{
    public List<int> MyMethod(int a, int b)
    {
        MyPrivateMethod(a, b, ref varList, ref someVal);
    }
    private void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我基本上想使用NUnit测试此公共方法。我正在使用NMock 2.0进行模拟。我该怎么做?因为,它在内部调用了我不想公开的此私有方法。或者,如果我将私有方法改为protected,有没有办法做到这一点?

Tho*_*ins 5

是的,“技巧”是使用保护而不是私有,然后继承该类并在执行受保护方法的新类上运行测试。这是使棕地和遗留代码可测试的一种非常常见的方法。

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            MyClassTestWrapped t = new MyClassTestWrapped();
            Assert.IsTrue(t.MyPrivateMethod(...));
            Assert.IsTrue(t.MyMethod(...));

            MockFactory _factory = new MockFactory();
            Mock<MyClassTestWrapped> mock;

            mock = _factory.CreateMock<MyClass>();
            mock.Expects.One.MethodWith(d => d.MyPrivateMethod());  // do the nmock magic here


        }
    }

    public class MyClass : IMyClassInterface
    {
        public List<int> MyMethod(int a, int b)
        {
            MyPrivateMethod(a, b, ref varList, ref someVal);
        }
// here change to protected
        protected void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval)
        {
        }
    }

    public interface IMyClassInterface
    {

    }

    public class MyClassTestWrapped : MyClass
    {
        public List<int> MyMethod(int a, int b)
        {
            base.MyMethod(a, b);
        }

        public List<int> MyPrivateMethod(int a, int b,ref List<int> varList, ref double someval)
        {
            base.MyPrivateMethod(a, b, ref varList, ref someval);
        }

    }
Run Code Online (Sandbox Code Playgroud)


k.m*_*k.m 5

现在,我基本上想测试这个公共方法(...)

这很棒。这就是你应该做的。暂时忘掉内部细节。从公共方法的角度来看,这两个摘要之间是否有区别?

// Your current implementation
public void MyMethod(int a, int b)
{
    MyPrivateMethod(a, b);
}
private void MyPrivateMethod(int a, int b)
{
    var c = a + b;
    // some more code
}

// Private method inlined
public void MyMethod(int a, int b)
{
    var c = a + b;
    // some more code
}
Run Code Online (Sandbox Code Playgroud)

谁打来电话(公开)MyMethod都不会注意到这两者之间的任何区别。最终结果是相同的。私有方法调用无关紧要,因为就公共API而言,它是无关紧要的。您可以内联表示私有方法,使其永久消失,从公共消费者的角度来看,没有任何变化。最终结果是唯一重要的事情。您可以测试代码使用者可以观察到的最终结果。没有一些内在的胡言乱语。

重要的实现是这样的:

正确设计的SOLID代码绝不会使您处于需要私人模拟的位置。问题的根源?设计不良。

来源:如何模拟私有方法-解决方案

是的 可悲但真实的是,您的设计并不是那么出色。根据您是否要更改它,可以采取以下几种方法:

  • 不要尝试嘲笑私人细节,而应关注公共API(对设计问题无济于事)
  • 提取私有方法进行分类,引入依赖关系(长期解决方案,改进设计并易于测试代码)
  • 使私有方法受到保护,按照其他答案中的建议在测试中覆盖(对设计问题无济于事,可能不会产生有价值的测试)

无论您选择哪个,我都由您决定。但是,我将再强调一次- 模拟私有方法不是单元测试,库或工具问题-它是设计问题,因此最好解决。


附带说明一下,(如果可以的话)不要使用NMock2。这是一个库,其最新更改自2009年开始。这就像一辆拥有30年历史的汽车,最后一次维修是在15年前。如今有更好的软件(FakeItEasy,Moq,NSubstitute)。