So, I was thinking of testing my getter and setters in a JUnit test. Yea, I know it is not recommended, but I thought that I could write a simple reflective iterator that could do it without much fuss.
What I show below is that maybe getter/setters should be tested, especially in Java which really does not have “real” properties. Further, by investigating a potential solution, I show that it doesn’t work, and the reason is that testing IS hard to do.
Anyway, just to save time, and not have to code this, I did a quick search and found that this has been done many times before. So I looked at one of the solutions, Scott’s. Very nicely done! With one line you can test a class’s property getters and setters. Then I noticed a problem.
In his approach he invokes the setter and then the getter, finally comparing that the values are the same. For example, if the property is a boolean, the test class will set it true, then read it and the value better be true. However, what if the value prior to your set was true, the object is initialized with true for the field value?
For example, I took a class and set field x to true via the default constructor, then I modified the setX method to not set the field value.
public class Fubar { private boolean launch = true; public void getLaunch(){ return this.launch; } public void setLaunch(boolean launch){ /* this.launch = launch; */ // broken! } }
Code at: git clone git://gist.github.com/1408493.git gist-1408493
In the unit test the getLaunch method still returned true. The getter/setter test did not fail; the test was bogus. Not only that, the fact that the setLaunch method did not work illustrates that sometimes testing setters is warranted.
Thus, the version of the program that controls the sports strategy will ship and the boolean that aborts a play cannot be set to false! (Edited, removed joke about war stuff; you can’t be too careful with all the craziness in the world).
In a recent presentation I gave on unit testing, I said that testing could be difficult. This is a great example of this. In this case, one should have followed analogous patterns in other fields. Thus, from semiconductor testing, for example, you would test gates by not just writing a 1 bit, you have to write 1 and 0 to make sure the gate is working.
The bullet points
- Java Getter/Setters are a programmer’s agreement, easily broken.
- A getter/setter could be collaborating with external resources or services.
- A getter/setter could be part of a JavaBeans property event broadcasting requirement.
- If it can be automated, what’s the fuss?
- Never underestimated what could go wrong.
- Improves test coverage levels and get a pat on head from management.
- Would you not test a five cent metal washer on an interplanetary star ship?
Updates
Feb 11, 2012: I’m using Scott’s solution in our test suite. I did modify the code a bit. Turns out that a JavaBean property is not so clear cut. If you have a getter and setter method pair but no actual target field, are those Javabean methods? Looks like the Java bean introspector will report these as bean accessors. Hmm.
June 7, 2013: There are two more issues with the above algorithm for testing getter/setters. First since the approach is for JavaBeans, there are issues with non-Javabeans.
1. If the getter/setters are based on interfaces, which they should be, one can’t automatically instantiate an object.
2. If the object doesn’t have a default constructor, one can’t automatically instantiate an object.
These are not insurmountable. The PropertyAsserter class has methods that take a class argument to use for testing a getter/setter.
Further Reading
- Unit Testing what will never happen?
- Should unit tests be written for getter and setters?
- Is there a Java unit-test framework that auto-tests getters and setters?
- Do You Unit Test Getters and Setters?
- Google search
Bill Evans Trio – Nardis – 19 Mar 65 (7 of 11)
Article on Bill Evans: http://www.chuckisraels.com/articleevans.htm