Should I test private methods or only public ones? [closed]
Asked Answered
M

31

414

I have read this post about how to test private methods. I usually do not test them, because I always thought it's faster to test only public methods that will be called from outside the object. Do you test private methods? Should I always test them?

Materse answered 19/9, 2008 at 19:56 Comment(2)
Possible duplicate of How do I test a class that has private methods, fields or inner classes?Cytolysin
"Should I test private helpers?" Yes. "Should I test private helpers directly?" It depends, generally if you can test them easily through the public interface, why test them directly? If it becomes complex to test all the aspects of helpers through a public interface, then has the component outlived its existence as a single unit?Biffin
F
397

I do not unit test private methods. A private method is an implementation detail that should be hidden to the users of the class. Testing private methods breaks encapsulation.

If I find that the private method is huge or complex or important enough to require its own tests, I just put it in another class and make it public there (Method Object). Then I can easily test the previously-private-but-now-public method that now lives on its own class.

Formularize answered 19/9, 2008 at 19:59 Comment(40)
Good point! But I do present in my answer a possible scenario where I like to keep those private methods private...Heldentenor
I do not get the Method Object pattern with how to test a private thing. The object won't be more able to call private method inside a new class...Materse
I disagree. Ideally, you write a quick test before you start coding a function. Think of typical input and what the output will be. Write the test (which shouldn't take you longer than a few seconds) and code until it gets the test right. There is no reason to abandon that style of work for private methods.Rocca
Saying that private methods do not need testing is like saying a car is fine as long as it drives okay, and it doesn't matter what's under the hood. But wouldn't it be nice to know that some cable inside is starting to get loose -- even if the user is not noticing anything? Sure, you can make everything public, but what's the point? You'll always want some private methods.Rocca
"A private method is an implementation detail that should be hidden to the users of the class." but are tests really on the same side of the class' interface as the "regular" (runtime) users? ;)Paulus
@Rocca Yes, you will. And the idea would be to achieve test coverage on your private methods by calling the public methods which depend on them. Calling a private method directly and testing its inputs/outputs probably (although I'm sure there are exceptions) means that your private method is doing too much and needs to be refactored. A common case that I see are converter methods that convert between two object types. That can be made private, but is better coded as a separate class with public methods. Testing becomes easier as well.Punak
The tests for a given class are not simply a 'user of the class'. They can have a much more intimate relationship. And as Frank says, how are you supposed to test + code as you develop if you can't test private methods?Der
But IMO there's no hard and fast answer. Take each situation on its own merits.Der
The danger of pulling out anything you want to test into another class is that you can end up with the overhead of over-engineering your product and having a million reusable components that never get re-used.Der
Comparing a piece of code to a car is wrong; code does not 'go bad' with time, it is eternal. If your testing of the public interface only goes as far as to determine that it 'looks okay' then your testing of the public code is insufficient. In this case testing private methods separately won't make the overall test complete no matter how hard you try. Concentrate on exhaustively testing your public code as a whole, using the knowledge of internal workings of the code to create the right scenarios.Liberate
One of the key reason for unit testing is to ensure contract is not broken or violated. If I have a class that exposes just one method, do I just test that one method? How can I ensure robustness with this level of unit testing? Private methods may be private to others, but it's not private to code within the class.Ravenravening
@jop, So, 7 years later, you still don't test your private methods?Demarcate
@Demarcate I still don't test my private methods. My second paragraph still holds though - if the private method begs to be tested, I extract it and test it.Formularize
@Demarcate you should still not test your private methods. If you are, you are designing your class wrong. It might be too complex. A class represents a unit, not a method, and to test the unit, you test all the possible inputs and outputs. Private methods are not inputs. All code paths in private methods are reachable through public methods - if not, then there's something wrong with your methods (or your test inputs).Sweeping
In my opinion every piece of code should be tested, because tests should guarantee that's all work well. Tests that covered only public methods may miss problems in your private methods.Northerly
Encapsulation and tests are orthogonal things. If a language doesn't allow you to easily test certain parts of the code it is a limitation of the language. No need to rationalize this.Fy
@Rocca Your example gave me some food for thought. First, I see that my car has at least two clients: a driver and auto mechanic. For me as a driver the only thing that the Car does is driving. So in the client code it goes like that: car.drive(). If I ask some repair shop to change the oil or spark plugs then the car should expose that functionality in order to consistently implement this task. So automechanic should invoke smth like car.changeSparkPlugs(new SparkPlugs()).Natie
@Rocca Second, as a consequence, using your example -- if some cable inside is starting to get loose -- then checking it is not a private method at all and absolutely not a not implementation detail -- at least for an auto mechanic. Third, here we smoothly go to the conclustion that a driver does not (should not?) care about any cables -- only an auto mechanic does. But the driver do must care about getting his car to repair service.Natie
@Rocca So we go to the fourth point: the car has at least two roles in two absolutely different contexts: one is when I'm driving it and the other when it is repaired (infoq.com/presentations/Making-Roles-Explicit-Udi-Dahan). But we can go even further. Is it still the same class? Or should we separate the functionality on two different classes, one per context?Natie
Private method are not out off bugs spells.Kashgar
I agree with @Juanpa. If I build a rocket and give it to a customer, he sees only public interface. It's important, that rocket is of a right size, can fit launch facility and has an engine. You wrote unit tests for this, which is nice. But rocket costs gazillions on money, and it will be pity, if you can only test its public interface before launch. That's why rockets have complex telemetry systems, and you can check every single piece of it before starting ignition.Delacroix
Programs are the same. It consists from large amount of blocks of logic. it's much easier to build a stable system from parts, when they behave correctly. I may want to check every bolt or nut before using it. So may I to do with functions. But beside that it should be economically reasonable to test every bolt or nut, there is one other issue: the lack of support from the language itself. The rocket is built with telemetry in mind. Why the language isn't?Delacroix
If the method is small enough I often test through some public interface that exists. If it gets complex or you start to see another domain emmerge, you can plop that domain into another class, then test it's interface. Ideally that is what you are testing and not the inner workings.Trimly
I downvoted your answer since you may encounter a situation where you wish to hide a complex internal implementation detail, but you still must unit test it - especially if the inputs to the public method do not map transparently to the inputs of the complex private method which eventually gets called by the public method .Forehanded
@RustyX - No! Code does go bad over time and it is not eternal. One of the most essential qualities of code is context. As the code around it changes, its context changes, and it can break just like a car under the hood. If you have tests set up, then you aren't surprised by it at brutally inconvenient times.Instantly
Testing private methods gives you finer granularity into your testing insights over just testing the public interface. Why anybody would reject deeper insight and finer granularity into monitoring the operation of their code because of some gratuitous academic reason sure beats the heck out of me!Instantly
What is suggested here is that the public interface be tested at every conceivable angle to cover every possibility of called private methods. The problem is, the public interface's private components could go deep with much complexity, doing things that become progressively harder to reach for discerning how to test all of it reliably. Every private layer that takes you further from the testable interface adds an exponential amount of complexity to this. But if you are allowed direct access to components at every layer, you come back to the first level of complexity for each of those layers.Instantly
@Instantly "No! Code does go bad over time and it is not eternal. One of the most essential qualities of code is context. As the code around it changes" That's not code wearing out over time. That's code going bad because of changes. Just like if I go add a supercharger to my car and the mechanic forgets to bolt the engine back in, that isn't the car wearing out over time. Also, if your had has such complexities, it should probably be refactored into multiple classes.Martlet
@Martlet - What? That's exactly what I said. In fact, you quoted me saying that very thing as I started to talk about code that changes. Are you disagreeing just to disagree?.. Good observation though about converting many layers of private complexity into separate classes. That is one way of making private functionality testable--by making it public somewhere else! :)Instantly
Is nobody really aware that by testing public methods, you are actually testing your private methods implicitly. I am new to TDD, but as far as I can see, the half is testing, but the other half is not developing. It is refactoring. So you can refactor mercilessly, and you can have many many private methods. And the coverage for these private methods are implicitly covered by tests. What is a unit anyway? Is it a class? A method? I would say it depends on the context. It should be a meaningful portion of code. Should we really test getters/setters unless they are doing something magical?Telephone
If you just move a method from private to public only because of testing. Then why is there access specifiers exists in different programming languages. Making private method to public breaks encapsulation not testing private method.Cyprus
"Comparing a piece of code to a car is wrong; code does not 'go bad' with time, it is eternal." @Liberate A piece of code may use external dependencies that can go bad after update.Dowse
The assumption that you code works well as long as its public interfaces are tested is wrong. Imagine you have a code that does really bad things, like doing lots of SQL queries, system calls, etc. That may be caused by a mistake in internal cache logic. However, you may not know about that if the code returns correct results and tests for its public interfaces are passed.Dowse
There is no "right" answer here. What there are though, are trade-offs. I'd rather think in terms of trade-offs and take it case-by-case. The general benefit of not testing private methods is that you can refactor them mercilessly and your tests won't break. When you test the implementation you add users of that implementation, which increases the costs of altering it. I think we all get that. In most cases, this makes it worth avoiding for me. Others noted that every private method should be testable by altering inputs on the public interface. But in my experiences this can be very complex...Seacock
In order to simulate every eventuality of behavior, you need to resort to mocking and stubbing, which can sometimes require deep knowledge of the implementation just to get right. When this happens there is still implementation bleed, and isn't that what we wanted to avoid? The 3rd scenario for me is when a method isn't really an "implementation detail", but is doing complex work based on complex conditions. In cases where you don't want anyone else using it, putting it in a separate class as public doesn't prevent use of it. What do you do then?Seacock
I disagree as well. Making private functionality public just to write a test is simply idiotic. Depending on the language you can risk the integrity of the application over a test case.Mucoid
This is holywar! We at our company are debating already 2 month - some of us for 100% coverage and testing all methods, other - for 60+ coverage and testing only public interface. And we still can accept 1 or other side. For me personally - you should test public method, and in rare cases protected(private) methods but only when there is difficult or complex logic(code). Because you will have to generate data provider with tons of cases to test all border conditions through public interface. Ideally you should avoid such methods -> refactor them, but sometimes you have to leave with itCompositor
I would like to add to the discussion. I find that testing private methods makes it harder for you to do the refactoring in future. In general you should be able to structure your private members inside the class as you want. And having tests that touch private methods prevents you from easily refactor the class. Note that I am talking about pure refactoring only - changing code structure without changing the code actually does. While that does not mean that some of your code should be left untested: you still can move some important pieces to a separate class or use mocks to verify stuff.Welldefined
I agree that private methods shouldn't be tested. What I'm curious about is the following: If I find that the private method [...] require its own tests, I just put it in another class and make it public there - how do you decide when a method should be made public? If you do this too much, your private implementation becomes a public API and you're essentially writing tests to test private implementation. But if you don't move methods to separate classes, you'll end up having slow E2E tests to test a few lines of change in some private function. How to find the right balance?Ipa
@Dowse "A piece of code may use external dependencies that can go bad after update." In this case it's better to test your piece of code using a mock object. Otherwise, you are dealing with an integration test and not a unit test. Other than that, in this example your piece of code did not "go bad". The external dependency did.Primaveria
S
344

What is the purpose of testing?

The majority of the answers so far are saying that private methods are implementation details which don't (or at least shouldn't) matter so long as the public interface is well-tested and working. That's absolutely correct if your only purpose for testing is to guarantee that the public interface works.

Personally, my primary use for code tests is to ensure that future code changes don't cause problems and to aid my debugging efforts if they do. I find that testing the private methods just as thoroughly as the public interface (if not more so!) furthers that purpose.

Consider: You have public method A which calls private method B. A and B both make use of method C. C is changed (perhaps by you, perhaps by a vendor), causing A to start failing its tests. Wouldn't it be useful to have tests for B also, even though it's private, so that you know whether the problem is in A's use of C, B's use of C, or both?

Testing private methods also adds value in cases where test coverage of the public interface is incomplete. While this is a situation we generally want to avoid, the efficiency unit testing depends both on the tests finding bugs and the associated development and maintenance costs of those tests. In some cases, the benefits of 100% test coverage may be judged insufficient to warrant the costs of those tests, producing gaps in the public interface's test coverage. In such cases, a well-targeted test of a private method can be a very effective addition to the code base.

Sacrarium answered 19/9, 2008 at 20:19 Comment(13)
The problem here is that those "future code changes" invariably mean refactoring the inner workings of some class. This happens so often that writing tests creates a barrier to refactoring.Drugi
Also, if you're continually changing your unit tests then you've lost all consistency in your testing and you'll even potentially be creating bugs in the unit tests themselves.Raised
@17 If the tests and implementation are modified synchronously (as, it seems. it kind of should be), there will be much less problems.Paulus
You cannot test private functions, the test requires access to the class function, and therefore requires it to be public.Augusto
The main purpose is to test the code. Right? if public methods invocation leads to testing of private methods then are we not good already. If there are some private methods that are not being called then it seems code design got some flaws.Hickok
Not convinced. YAGNIConsubstantial
That's a bad design smell. Why is your private method shared? In fact, how is it shared? Do you have a class with multiple responsibility? Do you have a class with unrelated behavior mixed together as a unit?Lenticular
@didibus, The private method is exposed to other private methods within the same class. Yes, the method is shared within itself and it should be well tested to ensure that the class itself works as expected.Demarcate
@Sauronlord, The reason you test private methods is because if you only test the public methods, when the test fails we do not know directly where the root cause for the failure is. It could be in either testDoSomething() or testDoSomethingPrivate(). This makes the test less valuable.. Here's more reasons for testing private #35071:Demarcate
@Demarcate It doesn't need to be tested to ensure that the class works as expected. The class needs to be well tested to ensure that the class works as expected. To all user of the class, the private method is not part of the class, only the outside exposed methods are.Lenticular
@Demarcate There's also a difference between testing your code, and having a continuous automated test process. You should obviously ensure your private method works, but you shouldn't have tests coupling you to the private method, because it is not part of the use case of the software.Lenticular
"Wouldn't it be useful to have tests for B also, even though it's private, so that you know whether the problem is in A's use of C, B's use of C, or both?". No, it wouldn't. From my experience, A and B will almost always break together. It's simply test duplication, and it's actually a barrier to refactoring quickly. And it's sometimes not just B...but B, C, D, E, F, G, H, and I. Nothing will make you pull your hair out faster than your test suite getting in the way of a refactoring. See my answer below for further detail.Urbane
Testing private methods may give a false impression that you have coverage when you actually don't because you never tested the integration of the helper with the public interface. Private methods should be tested, but why test them directly when you can test them through the public interface? :)Biffin
S
180

I tend to follow the advice of Dave Thomas and Andy Hunt in their book Pragmatic Unit Testing:

In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out.

But sometimes I can't stop myself from testing private methods because it gives me that sense of reassurance that I'm building a completely robust program.

Schaal answered 19/9, 2008 at 20:3 Comment(1)
I would recommend disabling unit tests that target private methods. They are a code coupling, and will burden future refactoring work, or even sometimes get in the way of feature addition or modification. It's good to write a test for them as you are implementing them, as an automated way for you to assert you're implementation works, but it's not beneficial to keep the tests as regression.Lenticular
U
107

I do not like testing private functionality for a couple of reasons. They are as follows (these are the main points for the TLDR people):

  1. Typically when you're tempted to test a class's private method, it's a design smell.
  2. You can test them through the public interface (which is how you want to test them, because that's how the client will call/use them). You can get a false sense of security by seeing the green light on all the passing tests for your private methods. It is much better/safer to test edge cases on your private functions through your public interface.
  3. You risk severe test duplication (tests that look/feel very similar) by testing private methods. This has major consequences when requirements change, as many more tests than necessary will break. It can also put you in a position where it is hard to refactor because of your test suite...which is the ultimate irony, because the test suite is there to help you safely redesign and refactor!

I'll explain each of these with a concrete example. It turns out that 2) and 3) are somewhat intricately connected, so their example is similar, although I consider them separate reasons why you shouldn't test private methods.

There are times testing private methods is appropriate, it's just important to be aware of the downsides listed above. I'm going to go over it in more detail later.

I also go over why TDD is not a valid excuse for testing private methods at the very end.

Refactoring your way out of a bad design

One of the most common (anti)paterns that I see is what Michael Feathers calls an "Iceberg" class (if you don't know who Michael Feathers is, go buy/read his book "Working Effectively with Legacy Code". He is a person worth knowing about if you are a professional software engineer/developer). There are other (anti)patterns that cause this issue to crop up, but this is by far the most common one I've stumbled across. "Iceberg" classes have one public method, and the rest are private (which is why it's tempting to test the private methods). It's called an "Iceberg" class because there is usually a lone public method poking up, but the rest of the functionality is hidden underwater in the form of private methods. It might look something like this:

Rule Evaluator

For example, you might want to test GetNextToken() by calling it on a string successively and seeing that it returns the expected result. A function like this does warrant a test: that behavior isn't trivial, especially if your tokenizing rules are complex. Let's pretend it's not all that complex, and we just want to rope in tokens delimited by space. So you write a test, maybe it looks something like this (some language agnostic psuedo-code, hopefully the idea is clear):

TEST_THAT(RuleEvaluator, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    re = RuleEvaluator(input_string);

    ASSERT re.GetNextToken() IS "1";
    ASSERT re.GetNextToken() IS "2";
    ASSERT re.GetNextToken() IS "test";
    ASSERT re.GetNextToken() IS "bar";
    ASSERT re.HasMoreTokens() IS FALSE;
}

Well, that actually looks pretty nice. We'd want to make sure we maintain this behavior as we make changes. But GetNextToken() is a private function! So we can't test it like this, because it wont even compile (assuming we are using some language that actually enforces public/private, unlike some scripting languages like Python). But what about changing the RuleEvaluator class to follow the Single Responsibility Principle (Single Responsibility Principle)? For instance, we seem to have a parser, tokenizer, and evaluator jammed into one class. Wouldn't it be better to just separate those responsibilities? On top of that, if you create a Tokenizer class, then it's public methods would be HasMoreTokens() and GetNextTokens(). The RuleEvaluator class could have a Tokenizer object as a member. Now, we can keep the same test as above, except we are testing the Tokenizer class instead of the RuleEvaluator class.

Here's what it might look like in UML:

Rule Evaluator Refactored

Note that this new design increases modularity, so you could potentially re-use these classes in other parts of your system (before you couldn't, private methods aren't reusable by definition). This is main advantage of breaking the RuleEvaluator down, along with increased understandability/locality.

The test would look extremely similar, except it would actually compile this time since the GetNextToken() method is now public on the Tokenizer class:

TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);

    ASSERT tokenizer.GetNextToken() IS "1";
    ASSERT tokenizer.GetNextToken() IS "2";
    ASSERT tokenizer.GetNextToken() IS "test";
    ASSERT tokenizer.GetNextToken() IS "bar";
    ASSERT tokenizer.HasMoreTokens() IS FALSE;
}

Testing private components through a public interface and avoiding test duplication

Even if you don't think you can break your problem down into fewer modular components (which you can 95% of the time if you just try to do it), you can simply test the private functions through a public interface. Many times private members aren't worth testing because they will be tested through the public interface. A lot of times what I see is tests that look very similar, but test two different functions/methods. What ends up happening is that when requirements change (and they always do), you now have 2 broken tests instead of 1. And if you really tested all your private methods, you might have more like 10 broken tests instead of 1. In short, testing private functions (by using FRIEND_TEST or making them public or using reflection) that could otherwise be tested through a public interface can cause test duplication. You really don't want this, because nothing hurts more than your test suite slowing you down. It's supposed to decrease development time and decrease maintenance costs! If you test private methods that are otherwise tested through a public interface, the test suite may very well do the opposite, and actively increase maintenance costs and increase development time. When you make a private function public, or if you use something like FRIEND_TEST and/or reflection, you'll usually end up regretting it in the long run.

Consider the following possible implementation of the Tokenizer class:

enter image description here

Let's say that SplitUpByDelimiter() is responsible for returning an array such that each element in the array is a token. Furthermore, let's just say that GetNextToken() is simply an iterator over this vector. So your public test might look this:

TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);

    ASSERT tokenizer.GetNextToken() IS "1";
    ASSERT tokenizer.GetNextToken() IS "2";
    ASSERT tokenizer.GetNextToken() IS "test";
    ASSERT tokenizer.GetNextToken() IS "bar";
    ASSERT tokenizer.HasMoreTokens() IS false;
}

Let's pretend that we have what Michael Feather's calls a groping tool. This is a tool that lets you touch other people's private parts. An example is FRIEND_TEST from googletest, or reflection if the language supports it.

TEST_THAT(TokenizerTest, canGenerateSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);
    result_array = tokenizer.SplitUpByDelimiter(" ");

    ASSERT result.size() IS 4;
    ASSERT result[0] IS "1";
    ASSERT result[1] IS "2";
    ASSERT result[2] IS "test";
    ASSERT result[3] IS "bar";
}

Well, now let's say the requirements change, and the tokenizing becomes much more complex. You decide that a simple string delimiter won't suffice, and you need a Delimiter class to handle the job. Naturally, you're going to expect one test to break, but that pain increases when you test private functions.

When can testing private methods be appropriate?

There is no "one size fits all" in software. Sometimes it's okay (and actually ideal) to "break the rules". I strongly advocate not testing private functionality when you can. There are two main situations when I think it's okay:

  1. I've worked extensively with legacy systems (which is why I'm such a big Michael Feathers fan), and I can safely say that sometimes it is simply safest to just test the private functionality. It can be especially helpful for getting "characterization tests" into the baseline.

  2. You're in a rush, and have to do the fastest thing possible for here and now. In the long run, you don't want to test private methods. But I will say that it usually takes some time to refactor to address design issues. And sometimes you have to ship in a week. That's okay: do the quick and dirty and test the private methods using a groping tool if that's what you think is the fastest and most reliable way to get the job done. But understand that what you did was suboptimal in the long run, and please consider coming back to it (or, if it was forgotten about but you see it later, fix it).

There are probably other situations where it's okay. If you think it's okay, and you have a good justification, then do it. No one is stopping you. Just be aware of the potential costs.

The TDD Excuse

As an aside, I really don't like people using TDD as an excuse for testing private methods. I practice TDD, and I do not think TDD forces you to do this. You can write your test (for your public interface) first, and then write code to satisfy that interface. Sometimes I write a test for a public interface, and I'll satisfy it by writing one or two smaller private methods as well (but I don't test the private methods directly, but I know they work or my public test would be failing). If I need to test edge cases of that private method, I'll write a whole bunch of tests that will hit them through my public interface. If you can't figure out how to hit the edge cases, this is a strong sign you need to refactor into small components each with their own public methods. It's a sign your private functions are doing too much, and outside the scope of the class.

Also, sometimes I find I write a test that is too big of a bite to chew at the moment, and so I think "eh I'll come back to that test later when I have more of an API to work with" (I'll comment it out and keep it in the back of my mind). This is where a lot of devs I've met will then start writing tests for their private functionality, using TDD as the scapegoat. They say "oh, well I need some other test, but in order to write that test, I'll need these private methods. Therefore, since I can't write any production code without writing a test, I need to write a test for a private method." But what they really need to be doing is refactoring into smaller and reusable components instead of adding/testing a bunch of private methods to their current class.

Note:

I answered a similar question about testing private methods using GoogleTest a little while ago. I've mostly modified that answer to be more language agnostic here.

P.S. Here's the relevant lecture about iceberg classes and groping tools by Michael Feathers: https://www.youtube.com/watch?v=4cVZvoFGJTU

Urbane answered 20/11, 2017 at 21:3 Comment(3)
The problem I have with listing "you could potentially re-use these classes in other parts of your system" as an advantage, is that sometimes the reason I mark a function is private is because I don't want it used by other parts of the system. This is a language-specific problem: ideally, this would be private to a "module", but if the language doesn't support that (e.g. PHP), my class represents the module, not the unit: the private methods are reusable code with their own contracts, but must only be reused within that class.Lacedaemonian
I understand what you're saying, but I like the way the Python community handles that issue. If you name the "private" member in question with a leading _, it signals "hey, this is 'private'. You can use it, but full disclosure, it wasn't designed for reuse and you should only use it if you really know what you're doing". You could take the same approach in any language: make those members public, but mark them with a leading _. Or maybe those functions really should be private, and just tested through a public interface (see answer for more details). It's case by case, no general ruleUrbane
I really like this answer.Coliseum
H
68

I kind of feel compelled to test private functions as I am following more and more one of our latest QA recommendation in our project:

No more than 10 in cyclomatic complexity per function.

Now the side effect of the enforcing of this policy is that many of my very large public functions get divided in many more focused, better named private function.
The public function still there (of course) but is essentially reduced to called all those private 'sub-functions'

That is actually cool, because the callstack is now much easier to read (instead of a bug within a large function, I have a bug in a sub-sub-function with the name of the previous functions in the callstack to help me to understand 'how I got there')

However, it now seem easier to unit-test directly those private functions, and leave the testing of the large public function to some kind of 'integration' test where a scenario needs to be addressed.

Just my 2 cents.

Heldentenor answered 19/9, 2008 at 20:9 Comment(5)
to react to @jop, I do not feel the need to export those private functions (created because of the division of a large too cyclomatic complex public function) into another class. I like to have them still tightly coupled with the public function, in the same class. But still unit-tested.Heldentenor
My experience is that those private methods are just utility method that is being reused by those public methods. Sometimes it is more convenient to split the original class in two (or three) more cohesive classes, making those private methods public in their own classes, and therefore testable.Formularize
nope, in my case, those new private functions are really part of the larger algorithm represented by the public function. That function is divided in smaller parts, which are not utility, but steps of a larger process. Hence the need to unit-test them (rather than unit-test the whole algo at once)Heldentenor
For those interested in cyclomatic complexity, I added a question on the topic: #106352Heldentenor
Oops, the url of the question changed due to a typo in the title! #106352Heldentenor
L
56

Yes I do test private functions, because although they are tested by your public methods, it is nice in TDD (Test Driven Design) to test the smallest part of the application. But private functions are not accessible when you are in your test unit class. Here's what we do to test our private methods.

Why do we have private methods?

Private functions mainly exists in our class because we want to create readable code in our public methods. We do not want the user of this class to call these methods directly, but through our public methods. Also, we do not want change their behavior when extending the class (in case of protected), hence it's a private.

When we code, we use test-driven-design (TDD). This means that sometimes we stumble on a piece of functionality that is private and want to test. Private functions are not testable in phpUnit, because we cannot access them in the Test class (they are private).

We think here are 3 solutions:

1. You can test your privates through your public methods

Advantages

  • Straightforward unit testing (no 'hacks' needed)

Disadvantages

  • Programmer needs to understand the public method, while he only wants to test the private method
  • You are not testing the smallest testable part of the application

2. If the private is so important, then maybe it is a codesmell to create a new separate class for it

Advantages

  • You can refactor this to a new class, because if it is that important, other classes may need it too
  • The testable unit is now a public method, so testable

Disadvantages

  • You dont want to create a class if it is not needed, and only used by the class where the method is coming from
  • Potential performance loss because of added overhead

3. Change the access modifier to (final) protected

Advantages

  • You are testing the smallest testable part of the application. When using final protected, the function will not be overridable (just like a private)
  • No performance loss
  • No extra overhead

Disadvantages

  • You are changing a private access to protected, which means it's accessible by it's children
  • You still need a Mock class in your test class to use it

Example

class Detective {
  public function investigate() {}
  private function sleepWithSuspect($suspect) {}
}
Altered version:
class Detective {
  public function investigate() {}
  final protected function sleepWithSuspect($suspect) {}
}
In Test class:
class Mock_Detective extends Detective {

  public test_sleepWithSuspect($suspect) 
  {
    //this is now accessible, but still not overridable!
    $this->sleepWithSuspect($suspect);
  }
}

So our test unit can now call test_sleepWithSuspect to test our former private function.

Legitimate answered 30/8, 2011 at 7:15 Comment(5)
eddy147, i really like the concept of testing protected methods via mocks. Thanks!!!!Friable
I just want to point out that in the original description of TDD, in unit testing, the unit is the class, not a method/function. So when you mention "testing the smallest part of the application", it's wrong to refer the smallest testable part as a method. If you use that logic, you might as well be talking a single line of code instead of a whole code block.Sweeping
@Matt A unit of work can point to a class, but also a single method.Legitimate
@Legitimate Unit testing comes Test Driven Development, where unit was defined as a class. As happens with The Internets, the semantics has expanded to mean a whole lot of things (i.e. ask 2 people what the difference between unit and integration testing is, and you'll get 7 answers). TDD was meant as a way to write software with SOLID principles, including Single Responsibility, where a class had a single responsibility and should not have a high cyclic complexity.In TDD, you write your class and test together, both the unit. Private methods are encapsulated don't have a corresponding unit test.Sweeping
"When we code, we use test-driven-design (TDD). This means that sometimes we stumble on a piece of functionality that is private and want to test." I strongly disagree with this statement, please see my answer below for further detail. TDD does not mean you are forced to test private methods. You can choose to test private methods: and that's your choice, but it isn't TDD that is making you do such a thing.Urbane
R
26

I think it's best to just test the public interface of an object. From the point of view of the outside world, only the behavior of the public interface matters and this is what your unit tests should be directed towards.

Once you have some solid unit tests written for an object you do not want to have to go back and change those tests just because the implementation behind the interface changed. In this situation, you've ruined the consistency of your unit testing.

Raised answered 19/9, 2008 at 19:59 Comment(0)
C
22

If your private method is not tested by calling your public methods then what is it doing? I'm talking private not protected or friend.

Catawba answered 19/9, 2008 at 20:4 Comment(2)
Thank you. This is a surprisingly underrated comment and especially still relevant, even after almost 8 years since it was written.Consubstantial
With the same reasoning one could argue to only test software from the user interface (system level testing), because somehow every function in the software would be executed somehow from there.Dermatology
D
19

If the private method is well defined (ie, it has a function that is testable and is not meant to change over time) then yes. I test everything that's testable where it makes sense.

For instance, an encryption library might hide the fact that it performs block encryption with a private method that encrypts only 8 bytes at a time. I would write a unit test for that - it's not meant to change, even though it's hidden, and if it does break (due to future performance enhancements, for instance) then I want to know that it's the private function that broke, not just that one of the public functions broke.

It speeds debugging later.

-Adam

Disclosure answered 19/9, 2008 at 20:4 Comment(2)
In this case, wouldn't it make sense to move that private method to another class, then just make it public or public static?Drugi
+1 If you don't test your private member functions and your test of the public interface fails all you will get is a result that's equivalent to something is broken without any idea what that something is.Harbot
L
12

I am not an expert in this field, but unit testing should test behaviour, not implementation. Private methods are strictly part of the implementation, so IMHO should not be tested.

Lilias answered 19/9, 2008 at 20:0 Comment(1)
Where is the implementation then tested? If some functionality uses caching, is this then an implementation detail and the caching is not tested?Dermatology
W
12

If you are developing test driven (TDD), you will test your private methods.

Whipperin answered 16/11, 2009 at 17:8 Comment(4)
You would extract the private methods upon refactoring agiletips.blogspot.com/2008/11/…Elwell
Not true, you test your public methods and once the tests pass then you extract the code in your public methods into private methods dureing the "cleaning" step. Testing private methods is a bad idea imo because it makes changing the implementation way harder (what if someday you want to change how you do something, you should be able to change it and run all of your tests and if your new way of doing the thing is correct they should pass, I wouldn't want to have to change all my private tests for this).Aldwin
@Tesseract, if I could upvote your comment more than once I would. "...you should be able to change it and run all of your tests and if your new way of doing the thing is correct they should pass" THAT is one of the major benefits of unit tests. They enable you to refactor with confidence. You can completely change the inner private workings of your class and (without rewriting all your unit tests) have confidence that you didn't break anything because all your (existing) unit tests (on your public interface) still pass.Canakin
Disagree, see my answer belowUrbane
T
11

We test private methods by inference, by which I mean we look for total class test coverage of at least 95%, but only have our tests call into public or internal methods. To get the coverage, we need to make multiple calls to the public/internals based on the different scenarios that may occur. This makes our tests more intentful around the purpose of the code they are testing.

Trumpi's answer to the post you linked is the best one.

Til answered 19/9, 2008 at 20:2 Comment(0)
N
9

Unit tests I believe are for testing public methods. Your public methods use your private methods, so indirectly they are also getting tested.

Nebraska answered 19/9, 2008 at 19:58 Comment(0)
P
8

I've been stewing over this issue for a while especially with trying my hand at TDD.

I've come across two posts that I think address this problem thoroughly enough in the case of TDD.

  1. Testing private methods, TDD and Test-Driven Refactoring
  2. Test-Driven Development Isn’t Testing

In Summary:

  • When using test driven development (design) techniques, private methods should arise only during the re-factoring process of already working and tested code.

  • By the very nature of the process, any bit of simple implementation functionality extracted out of a thoroughly tested function will be it self tested (i.e. indirect testing coverage).

To me it seems clear enough that in the beginning part of coding most methods will be higher level functions because they are encapsulating/describing the design.

Therefore, these methods will be public and testing them will be easy enough.

The private methods will come later once everything is working well and we are re factoring for the sake of readability and cleanliness.

Plaster answered 17/10, 2012 at 14:45 Comment(0)
L
6

As quoted above, "If you don't test your private methods, how do you know they won't break?"

This is a major issue. One of the big points of unit tests is to know where, when, and how something broke ASAP. Thus decreasing a significant amount of development & QA effort. If all that is tested is the public, then you don't have honest coverage and delineation of the internals of the class.

I've found one of the best ways to do this is simply add the test reference to the project and put the tests in a class parallel to the private methods. Put in the appropriate build logic so that the tests don't build into the final project.

Then you have all the benefits of having these methods tested and you can find problems in seconds versus minutes or hours.

So in summary, yes, unit test your private methods.

Locale answered 20/10, 2008 at 19:14 Comment(1)
I disagree. "If you don't test your private methods, how do you know they won't break?" : I know this because if my private methods are broken, then the tests that test my public methods that rely on those private methods will fail. I don't want to have to change my tests everytime I change my mind about how to implement the public methods. I also think that the main interest of unit tests is not to know specifically which line of code is faulty, rather it allows you to be more or less confident that you didn't break anything when making changes (to the private methods).Aldwin
M
6

You should not. If your private methods have enough complexity that must be tested, you should put them on another class. Keep high cohesion, a class should have only one purpose. The class public interface should be enough.

Mercator answered 21/11, 2014 at 15:11 Comment(0)
C
3

I understand the point of view where private methods are considered as implementations details and then don't have to be tested. And I would stick with this rule if we had to develop outside of the object only. But us, are we some kind of restricted developers who are developing only outside of objects, calling only their public methods? Or are we actually also developing that object? As we are not bound to program outside objects, we will probably have to call those private methods into new public ones we are developing. Wouldn't it be great to know that the private method resist against all odds?

I know some people could answer that if we are developing another public method into that object then this one should be tested and that's it (the private method could carry on living without test). But this is also true for any public methods of an object: when developing a web app, all the public methods of an object are called from controllers methods and hence could be considered as implementation details for controllers.

So why are we unit testing objects? Because it is really difficult, not to say impossible to be sure that we are testing the controllers' methods with the appropriate input which will trigger all the branches of the underlying code. In other words, the higher we are in the stack, the more difficult it is to test all the behaviour. And so is the same for private methods.

To me the frontier between private and public methods is a psychologic criteria when it comes to tests. Criteria which matters more to me are:

  • is the method called more than once from different places?
  • is the method sophisticated enough to require tests?
Catalano answered 6/5, 2013 at 23:22 Comment(0)
C
3

Yes you should test private methods, wherever possible. Why? To avoid an unnecessary state space explosion of test cases which ultimately just end up implicitly testing the same private functions repeatedly on the same inputs. Let's explain why with an example.

Consider the following slightly contrived example. Suppose we want to expose publicly a function that takes 3 integers and returns true if and only if those 3 integers are all prime. We might implement it like this:

public bool allPrime(int a, int b, int c)
{
  return andAll(isPrime(a), isPrime(b), isPrime(c))
}

private bool andAll(bool... boolArray)
{
  foreach (bool b in boolArray)
  {
    if(b == false) return false;
  }
  return true;
}

private bool isPrime(int x){
  //Implementation to go here. Sorry if you were expecting a prime sieve.
}

Now, if we were to take the strict approach that only public functions should be tested, we'd only be allowed to test allPrime and not isPrime or andAll.

As a tester, we might be interested in five possibilities for each argument: < 0, = 0, = 1, prime > 1, not prime > 1. But to be thorough, we'd have to also see how every combination of the arguments plays together. So that's 5*5*5 = 125 test cases we'd need to thoroughly test this function, according to our intuitions.

On the other hand, if we were allowed to test the private functions, we could cover as much ground with fewer test cases. We'd need only 5 test cases to test isPrime to the same level as our previous intuition. And by the small scope hypothesis proposed by Daniel Jackson, we'd only need to test the andAll function up to a small length e.g. 3 or 4. Which would be at most 16 more tests. So 21 tests in total. Instead of 125. Of course, we probably would want to run a few tests on allPrime, but we wouldn't feel so obliged to cover exhaustively all 125 combinations of input scenarios we said we cared about. Just a few happy paths.

A contrived example, for sure, but it was necessary for a clear demonstration. And the pattern extends to real software. Private functions are usually the lowest level building blocks, and are thus often combined together to yield higher level logic. Meaning at higher levels, we have more repetitions of the lower level stuff due to the various combinations.

Chuddar answered 6/4, 2019 at 10:11 Comment(3)
First, you don't have to test combinations like that with pure functions like you've shown. Calls to isPrime are truly independent, so testing every combination blindly is pretty purposeless. Secondly, marking a pure function called isPrime private violates so many design rules that I don't even know where to get started. isPrime should very clearly be a public function. That being said, I do get what you're saying regardless of this extremely poor example. However it's built off the premise you'd want to do combination testing, when in real software systems this is rarely a good idea.Urbane
Matt yes the example is not ideal I'll give you that. But the principle should be obvious.Chuddar
The premise isn't exactly that you'd want to do combination testing. It's that you'd have to, if you restricted yourself to testing only public pieces of the puzzle. There are cases where you'd want to make a pure function private to adhere to proper encapsulation principles. And this pure private function could be used by public ones. In a combinatory way, with other pure private functions perhaps. In that case, following the dogma that thou shalt not test private, you'd be forced to do combination testing on the public function rather than doing modular testing of the private components.Chuddar
J
2

If you don't test your private methods, how do you know they won't break?

Joby answered 19/9, 2008 at 19:58 Comment(5)
By writing through tests of your public methods.Nebraska
Those private methods are supposedly called by the public methods of the class. So just test the public methods that call the private methods.Formularize
If your public methods are functioning properly then obviously the private methods they access are functioning properly.Raised
If the tests of your public methods fail, you know instantly that something isn't correct at a lower level in your object/component/etc.Orangy
It's really nice, however, to know that it's an internal function and not just the external functions that broke (or conversely that the inner functions are fine and you can focus on the external).Disclosure
P
2

It's obviously language dependent. In the past with c++, I've declared the testing class to be a friend class. Unfortunately, this does require your production code to know about the testing class.

Paleface answered 19/9, 2008 at 20:1 Comment(2)
The friend keyword makes me sad.Orangy
This is not a problem if the testing class is implemented in another project. What's important is that the production code does not reference the testing class.Harbot
C
2

Public vs. private is not a useful distinction for what apis to call from your tests, nor is method vs. class. Most testable units are visible in one context, but hidden in others.

What matters is coverage and costs. You need to minimize costs while achieving coverage goals of your project (line, branch, path, block, method, class, equivalence class, use-case... whatever the team decides).

So use tools to ensure coverage, and design your tests to cause least costs(short and long-term).

Don't make tests more expensive than necessary. If it's cheapest to only test public entry points do that. If it's cheapest to test private methods, do that.

As you get more experienced, you will become better at predicting when it's worth refactoring to avoid long-term costs of test maintenance.

Cambria answered 10/6, 2019 at 2:22 Comment(0)
I
1

If I find that the private method is huge or complex or important enough to require its own tests, I just put it in another class and make it public there (Method Object). Then I can easily test the previously private but now public method that now lives on its own class.

Isia answered 19/5, 2011 at 16:14 Comment(0)
E
1

I never understand the concept of Unit Test but now I know what it's the objective.

A Unit Test is not a complete test. So, it's not a replacement for QA and manual test. The concept of TDD in this aspect is wrong since you can't test everything, including private methods but also, methods that use resources (especially resources that we don't have control). TDD is basing all its quality is something that it could not be achieved.

A Unit test is more a pivot test You mark some arbitrary pivot and the result of pivot should stay the same.

Eczema answered 2/11, 2018 at 2:2 Comment(0)
A
0

If the method is significant enough/complex enough , I'll usually make it "protected" and test it. Some methods will be left private and tested implicitly as part of unit tests for the public/protected methods.

Atticism answered 24/9, 2008 at 8:39 Comment(1)
@VisibleForTesting is an annotation for that. I'd not relax encapsulation for testing, rather use dp4j.comCroom
E
0

I see many people are in the same line of thinking: test at the public level. but isn't that what our QA team does? They test input and expected output. If as developers we only test the public methods then we are simply redoing QA's job and not adding any value by "unit testing".

Eupheemia answered 22/7, 2016 at 15:1 Comment(1)
The current trend is to reduce or have no QA team. These unit tests become the automated tests that run every time an engineer push the code on the master branch. Even with QA, there is no way they can tests the whole application as fast as automated tests.Materse
I
0

One main point is

If we test to ensure the correctness of the logic, and a private method is carrying a logic, we should test it. Isn't it? So why are we going to skip that?

Writing tests based on the visibility of methods is completely irrelevant idea.

Conversely

On the other hand, calling a private method outside the original class is a main problem. And also there are limitations to mock a private method in some mocking tools. (Ex: Mockito)

Though there are some tools like Power Mock which supports that, it is a dangerous operation. The reason is it needs to hack the JVM to achieve that.

One work around that can be done is (If you want to write test cases for private methods)

Declare those private methods as protected. But it may not be convenient for several situations.

Introduction answered 11/10, 2016 at 7:0 Comment(0)
T
0

The answer to "Should I test private methods?" is ".......sometimes". Typically you should be testing against the interface of your classes.

  • One of the reasons is because you do not need double coverage for a feature.
  • Another reason is that if you change private methods, you will have to update each test for them, even if the interface of your object hasn't changed at all.

Here is an example:

class Thing
  def some_string
    one + two
  end

  private 

  def one
    'aaaa'
  end

  def two
    'bbbb'
  end

end


class RefactoredThing
def some_string
    one + one_a + two + two_b
  end

  private 

  def one
    'aa'
  end

  def one_a
    'aa'
  end

  def two
    'bb'
  end

  def two_b
    'bb'
  end
end

In RefactoredThing you now have 5 tests, 2 of which you had to update for refactoring, but your object's functionality really hasn't changed. So let's say that things are more complex than that and you have some method that defines the order of the output such as:

def some_string_positioner
  if some case
  elsif other case
  elsif other case
  elsif other case
  else one more case
  end
end

This shouldn't be run by an outside user, but your encapsulating class may be to heavy to run that much logic through it over and over again. In this case maybe you would rather extract this into a seperate class, give that class an interface and test against it.

And finally, let's say that your main object is super heavy, and the method is quite small and you really need to ensure that the output is correct. You are thinking, "I have to test this private method!". Have you that maybe you can make your object lighter by passing in some of the heavy work as an initialization parameter? Then you can pass something lighter in and test against that.

Trimly answered 14/2, 2017 at 15:52 Comment(0)
E
0

No You shouldn't test the Private Methods why? and moreover the popular mocking framework such as Mockito doesn't provide support for testing private methods.

Enright answered 23/3, 2017 at 9:12 Comment(0)
D
0

It's not only about public or private methods or functions, it is about implementation details. Private functions are just one aspect of implementation details.

Unit-testing, after all, is a white box testing approach. For example, whoever uses coverage analysis to identify parts of the code that have been neglected in testing so far, goes into the implementation details.

A) Yes, you should be testing implementation details:

Think of a sort function which for performance reasons uses a private implementation of BubbleSort if there are up to 10 elements, and a private implementation of a different sort approach (say, heapsort) if there are more than 10 elements. The public API is that of a sort function. Your test suite, however, better makes use of the knowledge that there are actually two sort algorithms used.

In this example, surely, you could perform the tests on the public API. This would, however, require to have a number of test cases that execute the sort function with more than 10 elements, such that the heapsort algorithm is sufficiently well tested. The existence of such test cases alone is an indication that the test suite is connected to the implementation details of the function.

If the implementation details of the sort function change, maybe in the way that the limit between the two sorting algorithms is shifted or that heapsort is replaced by mergesort or whatever: The existing tests will continue to work. Their value nevertheless is then questionable, and they likely need to be reworked to better test the changed sort function. In other words, there will be a maintenance effort despite the fact that tests were on the public API.

B) How to test implementation details

One reason why many people argue one should not test private functions or implementation details is, that the implementation details are more likely to change. This higher likelyness of change at least is one of the reasons for hiding implementation details behind interfaces.

Now, assume that the implementation behind the interface contains larger private parts for which individual tests on the internal interface might be an option. Some people argue, these parts should not be tested when private, they should be turned into something public. Once public, unit-testing that code would be OK.

This is interesting: While the interface was internal, it was likely to change, being an implementation detail. Taking the same interface, making it public does some magic transformation, namely turning it into an interface that is less likely to change. Obviously there is some flaw in this argumentation.

But, there is nevertheless some truth behind this: When testing implementation details, in particular using internal interfaces, one should strive to use interfaces that are likely to remain stable. Whether some interface is likely to be stable is, however, not simply decidable based on whether it is public or private. In the projects from world I have been working in for some time, public interfaces also often enough change, and many private interfaces have remained untouched for ages.

Still, it is a good rule of thumb to use the "front door first" (see http://xunitpatterns.com/Principles%20of%20Test%20Automation.html). But keep in mind that it is called "front door first" and not "front door only".

C) Summary

Test also the implementation details. Prefer testing on stable interfaces (public or private). If implementation details change, also tests on the public API need to be revised. Turning something private into public does not magically change its stability.

Dermatology answered 14/2, 2019 at 22:31 Comment(0)
M
0

You can also make your method package-private i.e. default and you should be able to unit test it unless it is required to be private.

Micturition answered 7/5, 2019 at 23:15 Comment(0)
F
-1

Absolutely YES. That is the point of Unit testing, you test Units. Private method is a Unit. Without testing private methods TDD (Test Driven Development) would be impossible,

Fagan answered 25/5, 2012 at 10:58 Comment(3)
For TDD, a unit is most commonly defined as a class, or a group of related functions often called a module. Not a method.Downwind
I disagree, I use TDD and don't test private methods. The tests that fail make me write the public methods, once those pass I then extract the code in the public method into private methods for readability. What I like about this approach is if I ever feel like changing my private methods I can just run all my tests without having to change them to see if I broke anything.Aldwin
No, it wouldn't be impossible. See my answer.Urbane

© 2022 - 2024 — McMap. All rights reserved.