How many times did we hear the question:
Please
don’t do this at your workplace J
Let’s see the Pros and Cons now.
Pros:
- The test is green and I tested the piece of code that I wanted to test
- I did not compromise the security of my software(:P Whatever….)
- I am an expert because the official java tutorials say that only cool dudes like me can use reflection.
Cons:
- A simple rename done by anybody to the method, return type or parameter will break the test and I will have to come back to rewrite the test. This type of test is very difficult to maintain.
- I broke the Security of my software. What am I talking about??? How is that possible if the method still private in the production code?? Hacking the internals of a class is a security.
- See how long that test is. Imagine you have to do this for a longer and more complex method.
More drawbacks(Taken from Java official tutorials website):
“Should we test private methods?”
In this post I want to share with you my thoughts about this
question and how I think we should proceed when having this doubt.
Methods with the access modifier private are code as the rest of the application, so this mean that
they can potentially hide bugs. So after
a first impression my answer to that question is: “Yes, we should!”.
Wait, a second… before you get mad at me. I want to rephrase
my statement.
I think that question is completely not in place. Instead of asking “Should we test private methods?”, we should ask: “How do private methods affect our software testability?”
I think that question is completely not in place. Instead of asking “Should we test private methods?”, we should ask: “How do private methods affect our software testability?”
Let’s consider different approaches to deal with private
methods and see their pros and cons from the testability point of view:
Scenario 1 – Ok,ok
you leave me no choice but reflection
This is what the official Java tutorials say about reflection:
“Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.”
Ok, let’s give it a try, imagine we have some private
method, such as this one:This is what the official Java tutorials say about reflection:
“Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.”
Hhmmm…
So how to do this? Oh my god, do I really have to use reflection? Are you sure?
Let’s investigate a bit before making any decision.
Weeks ago I spent one full afternoon searching the internet looking for testability assurance pattern to test this in java. The only interesting discovery I did was that C# developers have a pattern for this called “Internals Visible To Attribute”. Unfortunately (Or maybe fortunately hehe…) that technique is not compatible with java.
There has to be an alternative, why can’t we just change the access modifier and test it normally?...
The common answer you get, when you ask that is: You will compromise security, you will break encapsulation, you are lazy…
Let’s investigate a bit before making any decision.
Weeks ago I spent one full afternoon searching the internet looking for testability assurance pattern to test this in java. The only interesting discovery I did was that C# developers have a pattern for this called “Internals Visible To Attribute”. Unfortunately (Or maybe fortunately hehe…) that technique is not compatible with java.
There has to be an alternative, why can’t we just change the access modifier and test it normally?...
The common answer you get, when you ask that is: You will compromise security, you will break encapsulation, you are lazy…
Ok,ok,you leave me no choice but reflection:
Pros:
- The test is green and I tested the piece of code that I wanted to test
- I did not compromise the security of my software(:P Whatever….)
- I am an expert because the official java tutorials say that only cool dudes like me can use reflection.
Cons:
- A simple rename done by anybody to the method, return type or parameter will break the test and I will have to come back to rewrite the test. This type of test is very difficult to maintain.
- I broke the Security of my software. What am I talking about??? How is that possible if the method still private in the production code?? Hacking the internals of a class is a security.
- See how long that test is. Imagine you have to do this for a longer and more complex method.
More drawbacks(Taken from Java official tutorials website):
Scenario 2 – There
is always a way out.
As mentioned in the previous scenario a design pattern that can help us testing private fields does not exist. But there are always ways out. Here I am going to suggest 2 and explain them:
As mentioned in the previous scenario a design pattern that can help us testing private fields does not exist. But there are always ways out. Here I am going to suggest 2 and explain them:
- Protect your method: Just change the access modifier to protected.
This will allow you to stub the method call and test using a pattern called
Subclass & Override. Basically on your test package, you will be creating a
fake that extends the class under test and then override using your
expectations. You will then use that fake on your test.
This is a very common breaking dependency technique, since that private method will for sure be called somewhere else within the class and present a dependency inside other method/s(Must be broken in order to increase testability).
I don’t agree with this being a security risk because various reasons, one of them is that probably that method should not be private or, is too long to be tested indirectly, or probably that method should not even be there.
The only disadvantage I see is a decrease in the quality of the design, but I will justify that as the price we need to pay when we build software without using TDD or having testability in mind.
This is a very common breaking dependency technique, since that private method will for sure be called somewhere else within the class and present a dependency inside other method/s(Must be broken in order to increase testability).
I don’t agree with this being a security risk because various reasons, one of them is that probably that method should not be private or, is too long to be tested indirectly, or probably that method should not even be there.
The only disadvantage I see is a decrease in the quality of the design, but I will justify that as the price we need to pay when we build software without using TDD or having testability in mind.
- Extract until you drop: Robert C. Martin in his book “Clean Code”,
describes a refactoring methodology called “Extract until you drop”, the idea
is refactor the code as much as possible until the point there the methods have
not more than 4 lines of code. He says that a line with just a curly braces
also count as a line. If you think about
it, your methods would be able to use an “if
else” statement of just one line in each of the clauses.
If we want to unit test, we need to have units. After doing this exhaustively on the method or class under test, we will probably see how that method was probably refactored into a new class, or maybe became so small that it can be tested indirectly via another method with no risk at all, since there are no longer inflection points(Places where logic of the software can potentially take a different path).
The main disadvantages of this approach will probably be that doing it probably would take too long, also on our way and specially if we are dealing with legacy code, we will need to use a lot of breaking dependency techniques and this will present a learning curve that will push us to break some of the design rules we were highly tight too in the past when the system was initially built. But the benefit will be visible at short, mid and long term.
If we want to unit test, we need to have units. After doing this exhaustively on the method or class under test, we will probably see how that method was probably refactored into a new class, or maybe became so small that it can be tested indirectly via another method with no risk at all, since there are no longer inflection points(Places where logic of the software can potentially take a different path).
The main disadvantages of this approach will probably be that doing it probably would take too long, also on our way and specially if we are dealing with legacy code, we will need to use a lot of breaking dependency techniques and this will present a learning curve that will push us to break some of the design rules we were highly tight too in the past when the system was initially built. But the benefit will be visible at short, mid and long term.
If you are concern about testability and you believe that
testability is the path to quality in modern software, then the right question
is How
do private methods affect our software testability?
Good read. Thanks for sharing it!
ReplyDeleteMáy lạnh Daikin
You're welcome. Glad you liked it :)
Delete