1

The consensus seems to be not to test private methods when doing TDD.

Should Private/Protected methods be under unit test?

I keep hitting this same scenario. I have a private method (as an example it switches all options to off). It changes lots of state and is called by a few public methods. The changes that the private method makes to the state will remain the same regardless of which public methods get called (all options get set to off).

What's the best way to test the functionality of this private method without adding many tests that effectively do the same thing?

btw, I'm using QUnit to test Javascript objects.

Here is an overly simplified version of my class.

http://jsfiddle.net/twistedinferno/UMgAx/

Edit

What I'm really trying ask here is not 'should I or shouldnt I test private methods' as that has already been answered and the answer to that is no. I want to know how do I best test each public method bearing in mind that many of the assertions will be the same due to the use of my private method. The same private method gets called by many public methods. Is it ok to have a lot of duplicate assertions to test the change of state that occurs when each one of many public methods call my private method?

new fiddle with tests http://jsfiddle.net/twistedinferno/JHzWh/

Community
  • 1
  • 1
atreeon
  • 21,799
  • 13
  • 85
  • 104

3 Answers3

4

Test the public methods.

Or, more generally, test the outwardly-visible interface for the object.

If the private method is used by the public methods, its use will be tested as a result. But the private method itself, being private, isn't a concern for anything outside of that object, including the tests.

These tests shouldn't know or care that such a private method even exists, let alone whether or not they're testing it. They should test all public functionality.

If the many tests are doing the same thing, might that be an indication that there's unnecessary overlap in the public functionality? Maybe there's room for re-factoring there? It's entirely conjecture without seeing any code, of course. Can you provide an example?

Edit

The additional assertions duplicate the same keystrokes, but the tests are distinctly different because they're testing different outward-facing functionality. You can always refactor out the duplicated assertions into a single function that each test calls. Sort of a custom aggregate assertion. As long as the public methods continue to have the same observable (and testable) behavior then that's fine. As soon as one changes, its test will need to change as well of course.

atreeon
  • 21,799
  • 13
  • 85
  • 104
David
  • 208,112
  • 36
  • 198
  • 279
  • here is an overly simplified fiddle http://jsfiddle.net/twistedinferno/UMgAx/ My real examples proved too large to add or too complicated to condense. There is certainly overlap in the public functionality but I'm unsure what to do about it. – atreeon Sep 06 '12 at 20:15
  • @TwistedInferno: In that example it looks like what you intend to test is the three latter functions, and the first function is the private one? (Admittedly I'm not well versed in JavaScript objects.) To the external observer, it doesn't matter that the private function even exists. The three public ones are tested. The fact that they all internally use the same private function is immaterial to the tests. (Indeed, the tests can also have a shared private function to validate commonly-expected results.) – David Sep 06 '12 at 20:54
  • yup, the methods with an underscore are private, the ones without are public (just a convention, the other option is closures which are less efficient in terms of memory). All the lights are public. Ok, so should I include four assertions for each light value for each public method? (that is 4 x 3 assertions) To me that is duplicating tests and doesn't feel quite right. – atreeon Sep 06 '12 at 21:04
  • @TwistedInferno: It's duplicating the same keystrokes, but the tests are distinctly different because they're testing different outward-facing functionality. You can always refactor out the duplicated assertions into a single function that each test calls. Sort of a custom aggregate assertion. As long as the public methods continue to have the same observable (and testable) behavior then that's fine. As soon as one changes, its test will need to change as well of course. – David Sep 07 '12 at 12:00
2

Given that you are practicing TDD, I would presume that each line of code in the private method in question would not have existed in the absence of a test that required it being written. That implies that there is no need to test the private function independently of the public interface.

Thanks!

Brandon

bcarlso
  • 2,345
  • 12
  • 12
  • Many thanks for your input but I'm not sure if I follow. The private method would exist even if there was no test specifically testing for it. The reason for having the private method is to encapsulate like behaviour and removing duplicate code. I agree, I don't need to test the private method independently but my problem is that I have many of the exact same assertions in each test for each public method and that doesn't feel quite right as I am duplicating assertions many times. – atreeon Sep 07 '12 at 08:55
1

I agree with bcariso and David. You shouldn't test, nor should you have to test, private methods.

One thing to note, is that if your private method is so big and important, that you feel you must test it, you should consider extracting it to be a public method of its own helper-class.

In Javascript, the same principle stands, only that you'd make it a publicly visible function, or a module (if you use that pattern).

Assaf Stone
  • 6,309
  • 1
  • 34
  • 43
  • Thanks Assaf, it's not that my private method is so big its just that it is repeating behaviour and therefor I need to repeat the tests. – atreeon Sep 07 '12 at 09:20
  • In that case, I would view it as a clear sign that you should make it a fully public function, as it is reused. – Assaf Stone Sep 07 '12 at 18:46
  • Thanks Assaf. It only repeats behaviour internal to the class so I'm not sure if making it public would be a good idea; the private method is not needed publicly. Maybe you could elaborate though... – atreeon Sep 07 '12 at 23:23
  • The idea is this - if you are doing the same thing twice, you should consider creating a utility function that you can use in multiple business functions. I suggested making it public only because JavaScript doesn't support the notion of "internal" encapsulation (like in C#). An example would be that if you need to access a web service (e.g. get the weather) in only one function, you can write the service-accessing code in that function. But if you find that you need it elsewhere, it warrants rewriting as a utility function that can be used anywhere. Make it part of your infrastructure. – Assaf Stone Sep 09 '12 at 17:26