-4

Here is a very basic example to illustrate my point

class SomeClass {
publicMethod1(param1, param2) {

    if (param1 === "some value") {
        // do stuff
    } else {
        // do stuff
    }

    this.privateMethod(true);

}

publicMethod2(param1, param2, param3, param4) {

    if (param3) {
        // do stuff
    } else {
        // do stuff
    }

    this.privateMethod(false);

}

privateMethod(param) {

    // do stuff

    let obj = database.getObject(param); // call to database

    if (obj.property === "random") {
        // do stuff
    } else {
        // do stuff
    }

}

}

I've done a bit of research into this topic but didn't find any people asking the exact question I'm asking. I think I'm clear that I should only be unit testing my public methods and not private ones. But I'm just wondering how I should be testing my public methods that make calls to private methods that are within the same class.

Should I simply be testing to make sure that private method was called? Or should I be delving into the logic of the private method to make sure I test every possible route of execution. And if it's a "yes" to the latter, I was wondering if it is common to reuse unit tests when dealing with private methods that are called multiple times (like in the example above).

EDIT: The answers to this question that everybody keeps linking seem to be solely geared around the question should I unit test my private methods? and what I'm asking is how exactly do I unit test my public methods that call private methods within the same class?

Jacob
  • 95

3 Answers3

1

You shouldn't be testing private methods at all. They are an implementation detail.

Test the public methods, to show that they do whatever they are supposed to do. If the public methods are passing the tests, then whatever private methods they are calling must also be working.

Simon B
  • 9,772
1

Should I simply be testing to make sure that private method was called?

Both yes and no here.

Private methods, as Simon points out, are implementation details. The correctness of the behavior of the public method is measured by evaluating the behavior, not how that behavior is achieved.

That said, if you are "path testing", then the set of paths that you consider will include the pathing variations within the logic of the private method, in combination with the pathing variations in the public method(s).

To first order, the number of paths through two integrated components is the number of paths through the first component multiplied by the number of paths through the second component.

This can get messy.

When this complexity gets out of hand, a common remedy is to modify the design so that you can substitute a simpler component in test so that you can focus your concentration on the complexity of the components individually. In other words, you modify the design so that your test code can change which function is called at the point where you normally hand over control to the private method.

In Test Driven Development, this notion of being able to substitute one implementation for another is treated as a first class concern - we deliberately choose designs that allow this substitutability where we think we need it for complexity control.

VoiceOfUnreason
  • 34,589
  • 2
  • 44
  • 83
0

You're right that, in most cases, you should write your tests against the public methods. The common rationale is that the private methods are just an implementation detail that should be free to change at any time, and you don't necessarily want to break your tests whenever you change the private methods in a class. Instead, you want your tests to flag cases when the public interface or behavior changes so you can evaluate that change. There's plenty of detailed discussion about this in various places.

Like most things, the amount of testing depends on the nature of the system you are building. If the system has a high level of desired reliability and robustness, you'll probably need to ensure a higher level of test coverage and a higher quality of test cases. For the most robust systems, you may want to consider various routes of execution through private methods as well, but write those tests against inputs to the public methods of your class. This could lead to many test cases that cover the same parts of a reused private method but would add more confidence in the ability to make changes to the implementation.

I don't think that there's value in asserting that a private method is called. That leads to the coupling between your tests and the private methods you'd find when explicitly testing the private methods. The behavior you want to test is the interface behavior specified by your public methods. That behavior usually doesn't include what methods (public or private) are called during execution.

Thomas Owens
  • 85,641
  • 18
  • 207
  • 307