-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?

7
  • @gnat Nope it does not
    – Jacob
    Commented Dec 15, 2020 at 5:44
  • 1
    Could you explain why this bit from the accepted answer on the linked question doesn't answer your question? "You should instead test your public interface. If the methods that call your private methods are working as you expect, you then assume by extension that your private methods are working correctly." Commented Dec 15, 2020 at 8:53
  • 1
    "Should I simply be testing to make sure that private method was called?" - absolutely not, the point of private methods is that they're internal implementation details. You call the public method, let it call the private method (or not, you don't care) and assert on the overall behaviour. You should be able to freely extract and inline private methods without changing the tests at all.
    – jonrsharpe
    Commented Dec 15, 2020 at 9:54
  • Jacob, if you want your question to stay here, you need to convince us by arguments why that other question does not answer yours. Currently, I think it does.
    – Doc Brown
    Commented Dec 15, 2020 at 15:39
  • 1
    @Jacob: I think your question is based on the wrong assumption that there should be a difference in unit testing when method calls a private method (or not). Actually, as soon as you refactor some code out of your tested method into a new private, it calls a private method - but the test stays the same. This holds also for the reverse refactoring. As soon as you got that misconception, I you probably understand why that other question provides indeed an answer to your question.
    – Doc Brown
    Commented Dec 16, 2020 at 12:12

3 Answers 3

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.

2
  • Yes you are right Simon, I got it loud and clear that I should not be directly testing my private methods... but what should I do in the case I laid out above, where a public method calls a private method? Whenever I call the public method to test it, should I be concerned about getting 100% code coverage within all the different routes of execution in the private method, or not?
    – Jacob
    Commented Dec 15, 2020 at 18:42
  • @Jacob If you need 100% code coverage (and most people don't bother unless it's safety-critical software), you should still be able to achieve that through calls to the public function. If you can't, then the private function must have redundant code that can't be called from anywhere. But with TDD, the aim is usually just to write the code that passes the tests. How it passes the tests isn't normally an issue.
    – Simon B
    Commented Dec 15, 2020 at 20:44
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.

1
  • Note that a private method wouldn't be considered a separate component. The test boundary should be the class's public API. If the private methods invoke methods on a collaborator, though, swapping out that collaborator for a test double would make sense.
    – jonrsharpe
    Commented Dec 15, 2020 at 15:28
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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.