Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Moq to verify execution of private methods

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.

like image 279
PianoFighter88 Avatar asked Jul 27 '11 15:07

PianoFighter88


2 Answers

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).

like image 97
PatrickSteele Avatar answered Nov 18 '22 22:11

PatrickSteele


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);
like image 36
Mark Bostrom Avatar answered Nov 19 '22 00:11

Mark Bostrom