使用Moq验证私有方法的执行

Pia*_*r88 5 unit-testing moq mocking private-members

我想测试以下逻辑(这显然是我的方法的精简版):

public void myPublicMethod(params) {

    if(some_condition)
        privateMethod1();
    else
        privateMethod2();
} 
Run Code Online (Sandbox Code Playgroud)

我已经模拟了方法中的所有其他依赖项,并且我已经设置了它以便我可以保证some_condition为true.我想要做的是验证我的privateMethod1()只被调用一次,并且根本不调用privateMethod2().这可能与Moq有关吗?

以下是有关该问题的一些注意事项:

  • privateMethod1()和privateMethod2()与myPublicMethod属于同一个类,因此我无法为此类创建模拟对象.
  • privateMethod1/2的主体包含来自包含这些和myPublicMethod的类的许多依赖项,因此将privateMethod1/2分解为它们自己的帮助器类将非常耗时.

有什么想法吗?提前致谢.我愿意接受这不可能做到,但我想知道这种或那种方式.

Pat*_*ele 15

不要测试私有方法.它们是该类的私有实现细节.您应该只测试执行公共方法的结果.只要您的结果符合预期,您就不应该关心如何获得结果.

构建对私有方法的测试将导致脆弱的测试,当您重构私有实现时(由于性能或其他原因),这些测试很容易破坏.

  • 我不想测试实际的私有方法; 我只想验证它是否被调用. (9认同)
  • 但是如果你不能从外部测试行为变化​​,那就意味着根本没有真正的变化。如果这只是不影响任何结果的实现细节,这应该已经被单元测试覆盖了。单元测试是为了确保像这样的实现更改不会破坏任何东西。您的公司政策可能应该禁止在没有单元测试覆盖的情况下更改功能/行为,而不是在不添加新单元测试的情况下。 (2认同)

小智 5

您的类有两个私有实用方法,它们封装了一些有用的行为,并且您正在测试的公共方法必须使用此行为。但是,当您进行测试时,您不希望这些方法具有正常行为,而是希望替换测试行为。这是一个典型的依赖案例。测试时,类内的依赖关系可能会出现问题。

因此,解决方案与外部依赖项相同:使用一种或另一种依赖项注入来将要测试的方法与实现该行为的私有方法脱钩。例如,可以声明两个私有委托来表示行为:

private Action Behavior1;
private Action Behavior2;
Run Code Online (Sandbox Code Playgroud)

在类构造函数中,正常行为是这样实现的:

public Foo (...)
{
    Behavior1 = privateMethod1;
    Behavior2 = privateMethod2;
...
}
Run Code Online (Sandbox Code Playgroud)

在公共方法中,调用委托而不是实际方法:

public void myPublicMethod(params) {
    if(some_condition)
        Behavior1();
    else
        Behavior2();
} 
Run Code Online (Sandbox Code Playgroud)

通过这样做,方法之间的绝对依赖性已被消除,因此现在它是可测试的。

所以现在,在测试中,创建测试对象实例后,您可以覆盖依赖行为:

Foo_Accessor testMe = new Foo_Accessor();

bool wasCalled1 = false

testMe.Behavior1 = new Action(() => wasCalled1 = true);

...

Assert.IsTrue(wasCalled1);
Run Code Online (Sandbox Code Playgroud)