7

I want to test the following logic (this is obviously a stripped-down version of my method):

public void myPublicMethod(params) {

    if(some_condition)
        privateMethod1();
    else
        privateMethod2();
} 

I have all of the other dependencies in the method mocked out, and I've set this up so that I can guarantee that some_condition is true. What I want to do is verify that my privateMethod1() is called exactly once, and privateMethod2() is not called at all. Is this possible to do with Moq?

Here are some notes on the issue:

  • privateMethod1() and privateMethod2() are within the same class as myPublicMethod, so I can't create a mock object for this class.
  • The bodies of privateMethod1/2 both contain many, many dependencies from the class that contains these and myPublicMethod, so breaking out privateMethod1/2 into their own helper class would be prohibitively time-consuming

Any thoughts? Thanks in advance. I'm willing to accept that this can't be done, but I'd like to know one way or another.

PianoFighter88
  • 73
  • 1
  • 1
  • 4

2 Answers2

18

Don't test private methods. They are private implementation details of the class. You should only test the results of executing public methods. As long as your results come out as expected, you shouldn't care how the result is obtained.

Building tests on private methods will lead to brittle tests that break easily when you refactor private implementations (for performance or other reasons).

PatrickSteele
  • 14,489
  • 2
  • 51
  • 54
  • 13
    I don't want to test the actual private method; I just want to verify that it is being called. – PianoFighter88 Jul 27 '11 at 17:03
  • Basically, I'm trying to comply with a policy at work that states that every code change requires a corresponding unit test (so that if the unit test breaks later, we are forced to really consider what/why we are making a change). My 'code change' was the conditional logic that results in the call of one of two private methods. – PianoFighter88 Jul 27 '11 at 17:05
  • 2
    But if you can't test the behavior change from the outside, it means that there is no real change at all. If this is only implementation detail that doesn't affect any result, this should be already covered by unit tests. And unit tests are to ensure that implementation changes like this don't break anything. Your company policy probably should forbid to change functionality/behavior without unit test coverage, not without adding new unit test. – NOtherDev Jul 27 '11 at 17:17
  • A, your clarification makes sense. privateMethod1 and privateMethod2 basically are two different ways to do the same thing, and the only thing that changes is 'how' they work to produce the same result, but the result itself is different. Thanks to you and Patrick for the help. – PianoFighter88 Jul 27 '11 at 17:51
  • Not sure this answer makes a lot of sense. If – d512 Dec 11 '14 at 20:38
  • The entire concept of exposing and mocking a class' dependencies makes your tests brittle. Not sure why supporting private methods is so evil in comparison. It's probably more just technical limitations of Moq itself being glossed over with "that's not something you should want to do" reasoning. Static methods meet a similar fate. Here's a more straightforward answer: http://stackoverflow.com/questions/21004323/test-calls-to-private-methods-with-moq – d512 Dec 11 '14 at 20:52
4

Your class has two private utility methods that encapsulate some useful behavior, and the public method that you are testing must make use of this behavior. However, when you test, you don't want the normal behavior from these methods, you want to substitute a test behavior. What you have here is a classic case of dependency. When testing, dependecies within the class can be problematic.

So the solution is the same as for an external dependency: use dependency injection of one kind or another to delink the method you want to test from the private methods that implement the behavior. For instance, two private delegates can be declared to represent the behavior:

private Action Behavior1;
private Action Behavior2;

In the class constructor, the normal behavor is implemented thus:

public Foo (...)
{
    Behavior1 = privateMethod1;
    Behavior2 = privateMethod2;
...
}

In the public method the delegate is called instead of the actual method:

public void myPublicMethod(params) {
    if(some_condition)
        Behavior1();
    else
        Behavior2();
} 

By doing this the absolute dependency among the methods has been eliminated, so now it is testable.

So now, in the test, after the test object instance has been created, you can override the dependent behavior:

Foo_Accessor testMe = new Foo_Accessor();

bool wasCalled1 = false

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

...

Assert.IsTrue(wasCalled1);