Testing private methods

January 7th, 2013  |  Published in .net, Testing

This has come up for discussion recently, my usual off the cuff answer of “don’t test privates, use your public api to test what you need” has not really been good enough.

This is my attempt at giving a detailed answer to this often contentious topic, my view of this has changed a couple of times of the last few years but as of today this is how I see it.

The basic rules for me are:
- Don’t test private methods directly
- If you think you need to, chances are you actually need to refactor.
- Don’t just make the private method public.

Something I have been asked a few times recently is “OK so I shouldn’t test private methods directly, but why is that?”.

Good question, the reasons that instantly come to mind for me are:
- Often implementation detail (We are interested that we get the result we are looking for, not interested in how it gets there).
- Makes unit tests fragile (with regard to refactoring).
- Generally agreed as a bad practice (A number of people who’s opinions I respect site it as bad practice, this has a strong impact on my point of view – in short I agree).

To try and give a better explanation I set up a contrived example, in doing so some points became more obvious.

If you need to run a lot of tests for a private method then doing so via a public method can have two negative side effects.

1. Your tests get muddied with lots of test that are actually for another method, this makes navigating and maintaining the tests more work.
2. Setting up your tests for the private method by testing the public method can become tricky.

What I mean is:

1. You will end up with a lot of tests for classx_methodx_{expected result}. The problem with this is when you change classx_methodx with a breaking change, you then need to change all the tests that relate to classx_methodx but you also need to change all the tests that relate to your private method, even though that code has not changed.

2. Chances are your test will Assert on a result. You know that your private method should return 22 with the given inputs, problem is the public method does some other stuff to the value returned from your private method before returning it. Meaning you need to make sure you do the same stuff that your public method does to the result so you can Assert that the value returned is what you expected. I’m sure you can see what a nightmare this could become.

So we are running into the problems described above, we could just make the private method public. This would mean we can test its logic directly and sidestep the two issue outlined. The problem I have with this is the impact it has on the public api, the method was private so it should be safe to assume that a consumer of your library / service / whatever doesn’t need to know about the method. I’m of the opinion that if they shouldn’t need to know about the method, then they shouldn’t see it, making it public will only make your public api harder for others to use.

The way I would get around this would be to refactor the method out as a class.

If the class is going to be of use outside of the application make it public if not then make it internal.

You can test internal classes by adding [assembly:InternalsVisibleTo("Test.Assembly.Namespace")] to the projects AssemblyInfo.

This gives you the separation you really needed, making all your tests more focused, maintainable and readable.

In conclusion, for the most part you will probably not come up against this issue as most private methods should be testable via your public api. If you start writing a lot of tests to test a private method via a public method, it’s probably time to start looking at refactoring the private method out to a class of its own.

Tags:

Leave a Response