DEV Community

loading...

Do you unit test private methods?

Daniel McMahon
Software Engineer @ Zalando SE
・1 min read

Encountered an interesting issue at work recently when it came to unit testing a new repo that was setup. The repo in question was relatively small and functioned as a basic cronjob, however in order to follow some best practices I decided to opt in for including some basic unit tests.

In doing so I mistakenly wrote a unit test for a private Python class signified with the standard underscore prefix! As I haven't coded in Python in a while I had forgotten about this syntax, but I was a little stunned to hear from a colleague that best practice seems to be to purposefully not test private methods.

I'm curious to hear the thoughts from the Dev community on this one? I get by their very nature you should probably opt to test the Class that the method belongs to end to end rather than opt for a unit test, but what about when you're looking for simple test functionality in a timely manner?

Curious to hear from the community on this one! (across different languages/frameworks too - not just Python)

Discussion (13)

Collapse
jefftian profile image
Jeff • Edited

You can access private methods using the object["prop"] notation in TypeScript:

class TestObj {
private method() { return "done" }
}

const testObj = new TestObj()

expect(testObj["method"]()).toEqual("done")
Enter fullscreen mode Exit fullscreen mode
Collapse
juliethqp profile image
JuliethQP

Thanks for, helped solve it

Collapse
yashwanth2714 profile image
Yashwanth Kumar

Why it works?

Collapse
jefftian profile image
Jeff

It's JavaScript feature that you can access properties by using [property]. And in the end the TypeScript will be transpiled to pure javascript which has no public, private differences.

Thread Thread
yashwanth2714 profile image
Yashwanth Kumar

Agree! However, I didn't expect that TS allow this because of it's strict Type Checking.

Collapse
rhymes profile image
rhymes

I don't test them anymore, I used to but I realized it's not needed.

Unit tests are supposed to test the unit of software that consists in the contract between you and the user of the functionality. The surface (be it a class, a function, a method, a package, or whatever) of the unit is whatever can be called from the outside.

That's the part that should be tested. Private methods are unknown by the outside world and the testing software is just another user of your unit.

In some languages you can't literally call private methods from the outside (which would make unit tests really tricky :D), Python doesn't really have them but we abide to the "underscore convention".

So no, you don't really need to test private methods. You can just call the public method that calls that private method and test if the expected output is there.

Collapse
phlash909 profile image
Phil Ashby

If you have code coverage measures in place, you can also eliminate dead code this way too - if those private methods never run with a full contract test in place - nuke 'em!

Collapse
szymach profile image
Piotr Szymaszek

The way I was taught and agree with, private methods should be invisible to tests. Tests should check things that can be publicly accessed and by providing different input data you should cover all (or at least feasible) angles with them. If you need to have that private method tested specifically, why not extract it and unit test it then?

Collapse
jessekphillips profile image
Jesse Phillips

My evaluation would include what the function does and what I would test for.

Yes I would look to test internal functions. Does the function take inputs and provide output based solely on that? Test it. Does it have external dependencies, requires a large interconnected object state, probably not then.

Collapse
renegadecoder94 profile image
Jeremy Grifski

Hey! I'm late to the party, but I was just in the process of writing an article on this exact topic when I found yours.

From what I've read, most people prefer to test the public API and ignore private methods altogether (sort of). In other words, they exercise the underlying private methods through the public interface through white box testing.

Of course, I'm a lot less against private function/method testing than most people. As with many debates in tech, I think there's always an edge case where it makes sense. For example, I was recently working on a utility class in Java that only had one public method: main. Do I go through the effort of trying to mock up the streams and feed in data, or does it make more sense to test the underlying structure before performing some sort of integration test? I opted for the latter, but to each their own.

Collapse
farenheith profile image
Thiago Santos

Another one late for the party here!

I work with TypeScript and I do test private methods. Why?

By our unit testing strategy, we consider the method as the unit of test and we mock anything that it calls. Also, we validate how this methods have been called, how many times, with which parameters, etc.. We do this to isolate each method and so the unit test gives a aimed diagnostic when it breaks.
So, we consider also the private methods as a unit, and we test it. In general it make the tests simpler as possible and help us to make simpler-to-test code.
It helps that in TypeScript we can access private methods by the "indexer" sintax, so, we don't need that much work to call them.

Collapse
stevezieglerva profile image
Steve Ziegler

I’ve read, have come to agree, that feeling the need to thoughly test private methods is probably a design smell.

Collapse
aetelani profile image
Anssi Eteläniemi • Edited

I don't think there is right answer. While coding a class, It is good thing to have 'glass box' access to everything and make a test case out of it rather than opening debugger or printing states.
After the code is developed, Ii is useful to save these tests as mementos. If there comes bugs later, private member tests help fixing the code and conform to the assumptions how code should work. This also helps avoiding regression.
Testing implementation internals is not necessary to do on every build, and can take lot of time. So it is preferable to make different test sets to different purposes and run when it fits the purpose.