1

I have looked at other discussions about this topic (on StackOverflow) however the other questions seem to be language specific whereas this is not language specific and I'm considering no longer using private methods, classes, and modules.

I want to test my private methods, classes, and modules so that I can more easily locate bugs. To allow me to do this I'm considering no longer using private methods, classes, and modules for two reasons, (1) I see no reasonable way of testing a private method, class, or module without injecting test code or using some sort of "magic" and (2) to improve code reuse. Note that I'm not considering no longer using private variables and properties because data needs protecting and does not provide behaviour therefore it does not need to be public during testing.

As a lame example, if you're writing a module called OneOperations that has two public methods addOne and subtractOne, and two private methods add and subtract. If you were not allowing yourself to have private methods you would put the two private methods into another module (basicOperations) where they are public and import those methods inside the OneOperations module. From this you should now be able to write testing code for all the methods in both modules without injecting code. An advantage of this is that the methods add and subtract can now be used in other modules by importing the basicOperations module (2 - improving code reuse).

I have a feeling this a bad idea, but I lack the real world experience to justify not doing this, which is why I've posted this question on StackOverflow.

So, how do you test your private methods, classes, and modules? Is not writing private methods, modules, and classes a potential solution?

Ryan Smith
  • 1,255
  • 2
  • 13
  • 16
  • I have the feeling that the issue is language-specific,since different languages have different ways of "opening" (breaking) methods "privacy".However, I think that 1) testing, in the sense of writing tests,should only apply to public methods.After all,they define the "semantic" you test,while private methods are only implementation.2) For debugging, this is irrelevant,since you can modify your code to see internal values.3)dropping private methods break abstraction and makes refactoring difficult.A private method is "part of an implementation",it makes no sense to let someone call it. – Victor von Cacahuete Sep 22 '13 at 11:39
  • And by the way,I think it's ok to break "privacy" for the sake of testing. – Victor von Cacahuete Sep 22 '13 at 11:39
  • possible duplicate of [How to unit test private methods in BDD / TDD?](http://stackoverflow.com/questions/1583363/how-to-unit-test-private-methods-in-bdd-tdd) – Joe Sep 22 '13 at 11:53
  • @Joe I saw that question earlier, but he was linking to C# and I wanted a more general answer. Thanks :) – Ryan Smith Sep 22 '13 at 12:15
  • The accepted answer to that question gives general advice, as do almost all the others; despite the tag, there's very little C#-specific content. – Joe Sep 22 '13 at 12:31
  • @Joe It doesn't consider the possibility of not using private methods, classes, and modules. – Ryan Smith Sep 22 '13 at 12:34
  • Two blog posts I have found relevant to this topic: http://www.brandonsavage.net/private-methods-considered-harmful/ http://blog.ircmaxell.com/2012/12/response-private-methods-considered.html – Ryan Smith Sep 22 '13 at 13:10

2 Answers2

1

1) Like in many other answers on this topic, the main question is why would you want to test your private methods? The purpose of a class is to provide some functionality to its clients. If you have comprehensive unit tests that prove that the public interface of this class behaves correctly, why do you care what it's doing in its private methods?

2) Your idea of not having private methods at all seems like cutting your leg off. For small projects it may be possible to have every tiny behaviour well separated and tested. But for large projects it's an overkill. What matters, is the domain logic behaving correctly.

Consider for example a method:

public double getDistanceSquared(Point other)
{
    return getDifferenceSquared(this.x, other.x)
      + getDifferenceSquared(this.y, other.y); 
}

private double getDifferenceSquared(double v1, double v2)
{
    return (v1 - v2)*(v1 - v2);
}

Ad1) Does it really make sense to unit test getDifferenceSquared method, if getDistanceSquared returns correct results for all test cases?

Ad2) Creating a separate class for calculating squared distance between doubles - in case there is only one place when it'll be used leads to a swarm of tiny classes, with millions of tests. Also, constructors of your domain classes will accept like 10 different interfaces for every tiny thing they're doing internally.

Maintaining all this is a lot of unnecessary work. Imagine that you would like to change the method of calculating the distance (maybe use some precomputed values). The behaviour of getDistanceSquared would not change. But you would have to change all of the tests of getDifferenceSquared even though you shouldn't have to care how is the distance being calculated, as long as it's calculated correctly.

Diving into minor details when it's not necessary makes you forgot what you're really doing - you lose the "big picture view". Value your time, and focus on important problems.

As a side note, also - the main concern of unit tests is not "locating bugs" as you suggest. They impose a clean design, provide an always up-to-date documentation of your code's behaviour and allow convenient refactoring giving you flexibility. Additionally they assure you that the code is working as you expect it to.

http://artofunittesting.com/definition-of-a-unit-test/

http://en.wikipedia.org/wiki/Unit_testing#Benefits

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
  • Thanks for your input, I really appreciate it. However, if I have a private method that supports two public methods and I make changes to many methods including those but the two public methods fail their tests because of the private method I can locate the problem without spending time debugging. I do think "cutting off my leg" is a bad idea though haha. I'm not sure if having lots of small modules is necessarily a bad thing but I understand what you mean by losing the "big picture view". – Ryan Smith Sep 22 '13 at 12:20
  • You're right, in general, lots of small classes is a good thing. Because that means that it's likely that they have precisely defined responsibility (refer to the Single Responsibility Principle). But no more than that - what I've meant, is that splitting one responsibility further into tiny classes seems too much. This is related to the debugging problem you've mentioned - if you need to debug a method to find out what's wrong with it, then this method, or it's containing class are probably too big. – BartoszKP Sep 22 '13 at 19:40
  • "if you need to debug a method to find out what's wrong with it, then this method, or it's containing class are probably too big" totally agree with that and I don't want to be making ridiculously small classes either. Thanks for your input, I really appreciate it. Thanks for the references too, that's really helpful. – Ryan Smith Sep 23 '13 at 08:33
1

There is another way to look at this, which is how do you generate a private method?

If we are following the TDD process properly, then the first thing we write is the test. At this point the test should contain all of our code, e.g.

public void ShouldAddTwoNumbers()
{
  (1 + 1).ShouldEqual(2);
}

Yes, that looks appalling. But consider what happens as we write is some more tests.

public void ShouldAddTwoMoreNumbers()
{
  (2 + 2).ShouldEqual(4);
}

Now we have something to reactor, so it can become

public void ShouldAddTwoNumbers()
{
  Add(1, 1).ShouldEqual(2);
}

public void ShouldAddTwoMoreNumbers()
{
  Add(2, 2).ShouldEqual(4);
}

private int Add(int a, int b)
{
  return a+b;
}

So now we have a private method that we can test inside our test class. It's only when you complete further refactoring to move the code out into your application, that the private becomes an issue. Most automated refactoring tools will offer you the option of changing the methods signature at this point, so that the private method is still accessible, because its not private.

(There is a fabulous exercise called TDD as if you mean it by Keith Braithwaite which I've just paraphrased above)

However, this isn't the end of our refactorings and development. One thing that we should be doing as we write and refactor our tests is to delete old tests, for example when functionality is duplicated. Another is to extract new methods so we don't repeat ourselves. Both of these can lead to scenarios where we have private methods back in the non-test code base.

So my advice is to be pragmatic, make the best decision you can for the code that you have in front of you. I wouldn't advise not creating private methods, but I would instead look at the factors that lead you to create them.

AlSki
  • 6,868
  • 1
  • 26
  • 39
  • Thanks for sharing that exercise. It seems to me that refactoring my code or injecting tests into it is the only way to test private methods. Thanks for your input @AlSki – Ryan Smith Oct 02 '13 at 15:02