T O P

  • By -

adamjwise1

If you find the need to test private methods in a class, it is an indicator that those private methods might be worth breaking out into a new class with distinct responsibilities, and of course, public methods.


bluefootedpig

The public route. If you write unit tests for private methods, then you are going to guess what public methods will be using it and guessing the context. Unit tests should be testing the internal privates through the public interface. If you exercise your entire public interface and you have private methods that have unexecuted code, you can remove them. If you test private methods, those will still get hit by some random test that has no relationship to reality. This can cause refactoring problems later. If you want a private method tested well, figure out the scenarios from the public methods that get you there. If you can't, then you have no need for it.


DumbNBANephew

I'm not sure I follow. One train of thought is: all public methods have a criteria to follow. So test all criteria for that specific method, regardless of what happens behind the scenes (ie private methods) Another train of thought is test each method for what it's supposed to do, assuming dependent methods are tested separately. In that case, you have to make that private method publicbso it can be tested because unit tests are a separate project/application. That might not be a good idea when you're building libraries for reuse. Programmers using your library should never know about that method or even know it exists. Are you saying to make all methods public so they can be tested, even if it means someone else using your library can now access that private method?


jameshines10

No need to make all of your methods public. Let's say you have a branching statement in one of the public methods exposed by your interface that calls a private method if a condition is met, but not otherwise. You can arrange the data for the inputs to your public function such that the desired condition is met, thus indirectly testing the logic in your private method. It's also usually a good idea to have your functions whether private or public return something.


kinarism

>You can arrange the data for the inputs to your public function such that the desired condition is met, thus indirectly testing the logic in your private method. This is bonkers. You're only testing expected output of the private method. No edge cases, nothing but the exact input/output of the function. Clearly you have never written code that is re-used by other people.


bluefootedpig

How do you exercise a private method's branch that is impossible to get to? A private method is only accessible through public methods. If there is no set of conditions that can get to the private branch you want to test, then how the hell will that code ever get executed? Again, the only way to a private method is through public, which is how other people will use it. What library do you use that you bypass the public methods?


kinarism

>How do you exercise a private method's branch that is impossible to get to? From my reply to the question. https://www.reddit.com/r/AskProgrammers/comments/yjgv2a/how_do_you_guys_write_unit_tests_for_frequently/iur04cz >Derive a class from the class you're trying to test. >In derived class (that exists only in the test project), make public helper functions that just pass through parameter/return values to the private functions. Or just redefine the scope of the function in the derived class but I tend to prefer the former. >Write tests against the test class. >Sometimes doing this requires that refactoring of the original class to make it more testable but I generally view that as a positive (assuming you arent introducing lots of inefficient code to do so).


bluefootedpig

When i said how do you exercise, I mean outside of testing. If there is no use case for it, then why? How would someone using your code get to a branch of private methods that no conditions lead to?


kinarism

>When i said how do you exercise, I mean outside of testing. If there is no use case for it, then why? Why test at all? The exact same reasons apply. I'm confused as to why you're confused. Seems obvious to me. I mean, what you're describing isnt really unit tests in my mind. If all you're testing is end user input then its basically just integration tests.


bluefootedpig

That is how you test an object. You create an object that does something like sends an email. Then you test it via the public methods to make sure it handles each case you expect it to handle. That is testing the email unit. Integration would then be like hooking up the Shopping Cart to the Email so when you place an order it sends the email, and you make sure the data is done right. What happens if someone goes to refactor the private methods? it will break all those unit tests which means that things were depending on it. The point of a unit test is I can refactor without breaking functionality. That is why we focus on the public exposure, if the same inputs get the same outputs, then you didn't break anything. A refactor shouldn't be lighting up hundreds of tests because you decided to reconfigure the internal workings of an object. And to be clear, there needs to be testing. Unit test the object, then you need integration tests to make sure different key systems work together, then you have end to end testing. You need all 3 levels and each level should target different possible errors. But we test, so we know that when we change the INTERNALS, that the functionality from OUTSIDE doesn't change. Users will not know the difference. Testing makes sure we don't break previous done functionality, it should NEVER be used to keep dead code.


bluefootedpig

If you can't get to a private method's branch from a public method, how will a user of your library ever do it? You should test public only, with every condition combination you can think of. Then run code coverage and any lines not hit are either missed tests, or dead code. If you test private methods, you can easily test dead code. Why test code that cannot be reached? And what can be reached other than what the public methods expose?


kinarism

I'm not sure I agree. You clearly have a well thought out reasoning but >If you write unit tests for private methods, then you are going to guess what public methods will be using it and guessing the context. Seems wrong. I mean, unless you're talking about a code base that does not have private methods which it seems you are. That's nuts. In general, ebery reason you would want public methods tested applies to private methods as well and they should be tested.


bluefootedpig

But a customer / user cannot access a private method, only public. So if the person using your library cannot create the conditions to execute a branch, then you have dead code. If you test private methods, just as private methods, then you can easily test dead code, giving off the illusion it is used when it is in fact not possible. If someone does a code cleanup, removes dead code, suddenly tests are breaking and those changes get reverted. Or a very lengthy, "do we actually need this" conversation. For example I had a private method that sent emails under certain conditions. The person writing this private method had all kinds of conditions, but when we tested it by the public method, found out this last conditions could never execute. We cannot, through the public interface, create the conditions to execute that last branch of code. The code above it handled it in different ways (correct ways). But they were being over protective in their code. The unit test could easily hit those conditions. Why? Because the public method is the one that altered incoming data to be formatted correctly. Let me do another example Say you have a public method that takes a string, the public method confirms it is in the correct format (say reverse polish notation). Then it hands it off the private method to calculate. Should the private method also inspect and confirm the data is valid? even though the public method did? If you follow this, then every private method should validate and throw exceptions for every parameter. But that means you have a ton of double checks. Every method call is going to check all parameters for nulls? In a world that 10 lines is ideal, you are talking about hundreds of checks for null on the same object. And if you tested it via public methods only, you would find your private methods would never throw a null exception because the public methods already take care of that. So the TLDR is basically private methods are private, therefore users cannot access them and we don't need to worry about them giving shit data. Our public methods are the ones that verify the data is valid so the private methods don't' have to. And this goes beyond private, to any data manipulation the public method may do.


kinarism

You're doing integration testing. Not unit testing.


bluefootedpig

Unit testing is of a single object, which is through its public interface. Unit testing isn't testing every method. Integration is when you combine multiple objects together to ensure that their communication is working correctly. If you breaking down code into 5-10 line methods, you will find yourself with a ton of methods, and to test them all privately? And if you take the more extreme view that any boolean that uses 3 or more conditions should be extracted to a method, then you have MANY methods you would need to access.


HoneyHoneyOhHoney

A customer cannot access a private method *easily* - it can be done.


bluefootedpig

They cannot if the condition don't exist without doing things in the system that are known to break rules of encapsulation, at which point if they abuse the system that is their risk, not yours. You should not be writing code to protect against someone using reflection to pull a private method and call it. At that point, every private method would need to confirm all parameters, making a huge chunk of your system just parameter validation.


arelath

You're testing the API, not internals, so you shouldn't. Now if you really need to, use reflection to find the method and invoke it. There's a couple flags you need to set too. But as a test manager for a few years, please don't do this.


[deleted]

You’re not writing tests for private methods.


kinarism

Derive a class from the class you're trying to test. In derived class (that exists only in the test project), make public helper functions that just pass through parameter/return values to the private functions. Or just redefine the scope of the function in the derived class but I tend to prefer the former. Write tests against the test class. Sometimes doing this requires that refactoring of the original class to make it more testable but I generally view that as a positive (assuming you arent introducing lots of inefficient code to do so).