ChatGPT解决这个技术问题 Extra ChatGPT

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

Closed. This question is opinion-based. It is not currently accepting answers. Want to improve this question? Update the question so it can be answered with facts and citations by editing this post. Closed 3 years ago. Improve this question

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?

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

L
Luke Girvin

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.


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.
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.
"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? ;)
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.
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.
D
Dave Sherohman

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.


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.
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.
@17 If the tests and implementation are modified synchronously (as, it seems. it kind of should be), there will be much less problems.
@Pacerier 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.
N
Nate

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.


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.
c
connexo

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):

Typically when you're tempted to test a class's private method, it's a design smell. 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. 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:

https://i.stack.imgur.com/h0RZH.png

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:

https://i.stack.imgur.com/g1G9o.png

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:

https://i.stack.imgur.com/Tbjqy.png

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:

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


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.
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 rule
I really like this answer.
V
VonC

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.


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.
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.
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)
For those interested in cyclomatic complexity, I added a question on the topic: stackoverflow.com/questions/105852/…
Oops, the url of the question changed due to a typo in the title! stackoverflow.com/questions/105852/…
C
Chacko Mathew

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.


eddy147, i really like the concept of testing protected methods via mocks. Thanks!!!!
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.
@Matt A unit of work can point to a class, but also a single method.
@eddy147 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.
"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.
1
17 of 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.


c
chrissie1

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.


Thank you. This is a surprisingly underrated comment and especially still relevant, even after almost 8 years since it was written.
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.
A
Adam Davis

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


In this case, wouldn't it make sense to move that private method to another class, then just make it public or public static?
+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.
m
maxbog

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.


Where is the implementation then tested? If some functionality uses caching, is this then an implementation detail and the caching is not tested?
J
Jader Dias

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


You would extract the private methods upon refactoring agiletips.blogspot.com/2008/11/…
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).
@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.
Disagree, see my answer below
T
Tom Carr

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.


s
scubabbl

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


d
dkinzer

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.

Testing private methods, TDD and Test-Driven Refactoring 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.


A
Adron

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.


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).
f
fernandezdavid7

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.


B
Billy Jo

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


By writing through tests of your public methods.
Those private methods are supposedly called by the public methods of the class. So just test the public methods that call the private methods.
If your public methods are functioning properly then obviously the private methods they access are functioning properly.
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.
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).
d
dvorak

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.


The friend keyword makes me sad.
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.
O
Olivier Pichon

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?


A
Andy

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.


m
magallanes

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.


C
Colm Bhandal

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.


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.
Matt yes the example is not ideal I'll give you that. But the principle should be obvious.
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.
t
tkruse

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.


佚名

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.


@VisibleForTesting is an annotation for that. I'd not relax encapsulation for testing, rather use dp4j.com
a
aemorales1

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".


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.
u
unflores

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.


C
Community

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.


S
Supun Wijerathne

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.


D
Dirk Herrmann

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.


Y
Yogesh D

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.