There is a philosophy out there of people who say that you should only ever test publicly accessible constructs. For argument’s sake let’s just talk about methods, but know that this extends to properties, members, constructors etcetera. I never understood this sentiment and it sounds like a brittle made up rule. I understand the idea behind it, I think it’s adorable, but misguided. It makes everything harder than it needs to be for absolutely no reason. The reasoning I have gotten is some form of the following on different occasions:
You should only test publicly accessible methods. Private methods should not be tested directly, but indirectly via the public methods that call them.Developers with rose colored glasses on
That’s cute, but you’re wrong
There is absolutely no reason to restrict your testing. In fact, I will go as far as to say that by not testing your private methods you are doing yourself a disservice for the sake of some romanticized view of testing. Of course those who believe that you should only test your publicly accessible methods will usually retort with something to the effect of, “If you are testing your private methods directly there is something wrong with your design.” Orrrrr… maybe I just want to test my private methods directly for the sake of simplicity?
My point here is, there is zero benefit to NOT testing your private methods. One of my biggest pet peeves is when I see people making what should be private methods public just so they can test them without being barked at by a testing hawk who spews the same quoted nonsense from above. Well, I am saying you are wrong and you have no basis for this demand on the rest of us.
Forced bad coding
When writing code I make everything private and only make things public that SHOULD BE public. I refuse to make my methods publicly accessible just for the sake of unit testing or doing something as unnecessary as having a façade method just for testing. No one should have to be chastised for wanting to test their code, it’s counter intuitive and I think all of the developers out there who harp on this point need to move on and become modernized. Not being able to test private methods makes as much sense as forcing me to do any of the following things which basically are dead standards at this point:
- Using the
thiskeyword for absolutely no reason other than “It’s what I used to do in C or C++”, great – not necessary.
- Adding default empty constructor when you don’t need to.
- Not using auto-properties when they have been available since dot net 3.0 which was in late 2007.
BLOCK_LETTERSfor constants – completely unnecessary. Yes, I used to do this too, I learned it in C, you don’t need to do it anymore it’s okay.
- Hungarian notation. I still think this has its place for naming UI elements, but the common verdict is don’t use it in code.
This list can go on, but I think you get the idea…
Instances where testing private methods is the only way
I have been in situations where I start working a new job only to be met with a bunch of untestable code. Unit testing was obviously never implemented and no one was thinking about it (or they were ignored when they brought it up – looking at you management). This is actually where I realized that only testing publicly accessible methods was incredibly misguided. I was in a situation where every inlet that was public was so poorly written the unit tests were useless and provided me no usable feedback on whether or not my test was successful.
If you attempt to use red, green, refactor at the top level you will do more harm than good in a brown field system. Therefore, you do the opposite and you work from the inside out. To do this effectively you test the innards which are usually PRIVATE therefore you must test private methods. This is especially true for code bases where there is no dependency injection because the code base is from the year 2000 or earlier. So let’s stop pretending our code base is a black box when it isn’t. I can see inside, it’s called source code.
How to get started testing private methods
I have created two base classes which are mostly identical to one another that I use for testing private methods. I catch crap from developers for using it, but they are always the developers who share the quoted philosophy above. I am always willing to change my opinion, but not if I am not given a solid argument. Therefore, on to the base classes that I use.
I am providing the base directory for where these files should continue to live on my GitHub account:
The links below could go dead if in the future I end up changing it, but I am pretty sure they will stay in the same directory/path of the repository.
|TestBaseForNUnit.cs||Testing base class for NUnit.|
|TestBaseForXUnit.cs||Testing base class for XUnit. I included some other methods that XUnit just won’t provide for reasons. Again, it comes down to philosophy. XUnit does not believe in |
In general, both classes have the same code in them and I am going to try to keep them in sync. I am only putting in generic methods and properties in this testing base. It is made abstract on purpose because you shouldn’t instantiate it, but that’s just my preference. With this code you can invoke private methods and static private methods. I am just using reflection.
It’s not perfect
- I ran into a problem the other day which I will try to fix eventually where my testing base does not handle overloaded methods. Not a big deal, I just haven’t sat down to work on it yet.
- You have to use a string for the method name. I hate this, but again it’s better than nothing. I really wish you could use
nameof()for private method names, but you can’t. Hence the need for a string. The good news is, if the method name changes then the unit test will fail with a not so friendly “Exception has been thrown by the target of an invocation” error. This makes sense because I am using reflection.
Things I want to do
I have run into some weird testing scenarios where my hands are still tied, and just like using reflection for private methods, I am trying to find solutions to the following:
- Unit testing extension methods – I don’t remember the exact situation right now, but I have run into a problem where unit testing an extension method wasn’t possible.
- Mocking extension methods – this is just insanity. It is borderline dangerous to do because it seems like the only option is to inject code at run time to overwrite your extension method in memory. There is a lot of problems with this, but I will keep thinking about it. I don’t want to provide potentially unsafe code.