I originally posted this post on my blog a long time ago in a galaxy far, far away. It's part of an ongoing series I've been publishing, called Unit Testing 101.
Trying to test private methods causes a lot of confusion.
That's a common question we all have made when finding unit testing for the first time. These days, I found that very same question on Reddit:
Can someone explain to me why unit testing our private methods is bad?
And here's my full answer:
Because we don't want to break encapsulation.
If you have a private method, how are you going to call it from a test class or method?
It's private. You can only access it from inside the same class. That's the whole point of access modifiers: restricting access to the fields and properties that hold the internal state of a class.
And please don't make your private methods public and static to call them directly inside unit tests. They're private for a reason, right? We don't want the rest of your code to use them directly.
Exposing internals is the most common mistake when writing tests. I've seen it and fixed it before.
Let's take the HasAdmin()
method from the question as an example,
private bool HasAdmin(List<string> relations, bool hasPermission)
{
// Beep, beep, boop...
}
Unless HasAdmin()
has 0 references—if that's the case, you should remove it—another method from the same class is calling it. And you can trace the chain of method calls back to a public method.
HasAdmin()
, or any other private method down in the chain of method calls, is changing something that you can observe from public methods. Probably it's affecting a return value or changing an internal state you can inspect with getters. That's what you should test instead.
To test HasAdmin()
, create a User
object with the right relations and permissions, call the public methods you have, and check what should change when your user is an admin or not. Maybe you return additional data only admins can access or finish an action without throwing a UnauthorizedAccessException
.
You test private methods indirectly while testing the observable behavior exposed through public methods.
Et voilà!
Download your free copy of my ebook, Unit Testing 101: From Zero to Your First Tests. It covers all the basics to help you write your first unit tests in C#. Plus, get 5 bonus lessons delivered straight to your email to make your first tests even better.
I think this is truly reflect, which is one weakest point of OOP concept.
Imho, a similar reason to avoide the OOP programming as possible.
Because even with the lightest object we are attach our functions to the data, and part of these data are protected also. So handling this data is bit painfull because always need to care about lifecycle of object not just the the data.