1

After reading several threads on the subject on this site, I have come to the following conclusion :

To test Private Methods, one has two choices :

  • Use the PrivateObject but the Testing Tool of VStudio 2012 is crappy when having lots of tests and it is advised to use NUnit instead But PrivateObject uses a namespace which comes in collision with those of NUnit for Asserts for example, so, it should be avoided.

  • Transform all private members in protected members (attributes + methods) and make a wrapper class inherits the tested class and call the protected method through public method.

The second choice works BUT it seems to me very awkward to break OO encapsulation for Test driven reasons.

I am not asking to discuss whether private methods should be tested or not (point already debated in other threads) , or use another tool, or defend VStudio (idem).

I'd rather hear your comments on sacrificying OO principles over testability.

Thank you.

charly's
  • 279
  • 1
  • 3
  • 16
  • Consider making them public methods on a *new class*. Methods that are complex enough that you want to unit test them but that don't make sense as part of the public API are often a sign that your class is doing too much. Creating a separate class means you can test them as ordinary public methods but that clients of the original class can't access them. – Quartermeister Jun 20 '13 at 14:12

5 Answers5

5

I can't understand why private methods should be tested. In my most honest opinion, you should not break your OO principles just to test private methods. Why? Because you might be breaking some functionality/architecture or worse, jeopardizing the security by increasing your supposed to be private methods' visibility.

Only exposed API (public) should be unit tested. Because these methods are the only methods that is seen and can be accessed anywhere. Anything private is used by these public methods. These methods represent your business processes, API. So it makes sense to test only public methods since these are the methods that will and can be accessed by the outside.

Again, private methods which are most likely used by your public methods should already be inside your unit testing scope when testing your public methods/exposed API.

I'm speaking at least in an OO paradigm perspective. Of course, there will be arguments that Unit Testing is more suitable in a procedural/modular paradigm because unit testing, by its pure definition, is testing every bit of unit of your system.

aiapatag
  • 3,355
  • 20
  • 24
  • 2
    I would say anything which contains business logic should be unit tested, be it private or public. If some bit of code is going to be touched and have an impact on your system you want to make sure its gonna work. Although I do agree that usually having private methods with business logic concerns is often a cause of bad design or a code smell and should be moved elsewhere to be mockable. – Grofit Jun 20 '13 at 12:57
  • private methods should just be bits and pieces to complete your business logic which should be exposed by your public methods. – aiapatag Jun 20 '13 at 12:59
2

Whenever I have tested private methods I have just written a reflection based extension method in the test project and just used that to expose the function, as really the method is just the starting point, its what happens within there that you are interested in testing, so the how is not as important as the why in this case. As alot of the time people say if something is private there is something wrong, it should either be in its own class as its got its own responsibility etc, however you can worry about the why later...

Anyway as for tools I would recommend staying away from MSTest or Microsoft integrated testing frameworks, and opt for a open source one like Nunit etc.

This is mainly because in a lot of cases you want to automate your builds and run them on a build server, such as teamcity or jenkins (or in some rare and crazy cases TFS). However if you were to try and run your MSTest based tests on your build server it will not let you without installing visual studio, as that is where the dlls required for testing are held. So I dont think your build server should have to have your IDE installed just to run some tests, so in this case it makes sense to use something which is self contained and simple, such as Nunit as then you just need the dll and runner, job done.

== Edit ==

Incase you do decide to just get your private method via reflection (extension or hard coded), here is a link which should show what I mean:

How do I use reflection to invoke a private method?

I would not bother changing your code, as you have it private for a reason (be it right or wrong), so you may as well just take 5 mins to make an extension method and do your tests, then if you realise having it private IS a problem, you just remove the extension call in your tests.

Community
  • 1
  • 1
Grofit
  • 17,693
  • 24
  • 96
  • 176
1

Think about what logic you want to test. If that logic is inside a private method, consider making it public. Your test runner is like a user of your application, so why not giving it access to the code. If you only need the result of that private method in another public method, maybe it's sufficient to only test the public one.

studert
  • 137
  • 4
0

It's obviously a matter of opinion. However to play devil's advocate.. in defense of approach 2 above.

Often testing private methods can be simpler than testing the public API and therefore lead you to smaller, tighter tests which you can have better confidence in.

Kevin
  • 4,586
  • 23
  • 35
0

I'd recommend to keep testing private methods at a minimum. By coupling your tests to the internal implementation they become very brittle and many of your tests will probably break whenever you decide to refactor your code.

This often either leads to not refactoring anymore because it breaks too many tests, or to not write unit tests anymore because it prevents you from refactoring.

Test the behavior through the public API of your classes. Not the implementation details.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108