Testing Getters and Setters?

by Jeff Langr

December 05, 2007

You’ve heard many developers claim they don’t test getters and setters. Correct–you should probably not write direct tests for these things. The primary reason is that they do not (usually) represent behavior; a setter or getter is (usually) just a means of exposing an attribute.

Let me touch on a few points.

  • “Getters and setters can’t possibly break.” Wrong! Been there done that. Try misspelling the formal argument name in a setter, e.g. “X” instead of “x.” this.x = x; will compile (you might get a warning), but it will do nothing on execution. If you assume that this sort of code can never break, you will spend lots of time looking elsewhere for the problem–been there done that! 🙂 Still, this isn’t a compelling reason to write a direct test.

  • “Don’t test getters and setters” should probably be quantified with “directly.” More or less everything, in effect, should be test-driven. That is, code should not come into existence without first having a failing test. So, perhaps tests against a method in another class drive the need for the getter, and that’s fine. But you should never blindly add getters/setters to a class without a reason. (The code generator utilities in Eclipse and other tools should probably be painful to use, to dissuade you, and they sort of are.) If you use a dumb framework that insists on you creating getters/setters that aren’t directly called by your code, consider a better framework.

  • Many getters have interesting logic (e.g. lazy initialization), as do setters (although this is often a riskier design choice). I’m a firm believer in verifying that these “trivial” idioms actually work; I’ve seen enough broken initialization attempts. You should test-drive these, and probably directly so (and maybe even ensure they are comprehensively re-tested within the context that they are used).

  • I always write tests for constructors, for a few reasons. First, it’s a good, simple place to start. It allows you to get a quick test in place and build an instantiable class within a minute or two. Second, a class without tests often suggests to other developers that maybe we don’t need to worry about writing any tests for that class. “Oh yeah, I guess we need to add to the tests for this class.” Third, having to write constructor tests can discourage people from putting any complex logic in constructors, something that’s not usually a good thing to do. 🙂 Fourth, and most importantly, tests for constructors document all of the possible means of creating instances of a class, information that can be difficult to derive otherwise. You’re cheating your fellow developers by skimping on these tests.Having tests for my constructors means that I effectively test-drive getters, as they are the best means to verify construction.

So, should you test-drive getters and setters into existence? Yes, usually indirectly. As long as they get test-driven into existence, you’ll eventually find the problem if they hide a defect. Directly, only if the getters and setters are interesting.

 

Comments

Bartosz Bańkowski December 13, 2007 at 08:27am

If someone asks me “Do you test setters/getters?” or “Do you change your methods from private to protected in order to test them?” it is a sign for me that this person is probably not doing test-first.

If you do TDD properly, you test behaviors, based on requirements (user stories, acceptance criteria). As you wrote – getters/setters don’t represent them. While making the class to fulfill the test getters and setters are created (if needed). That way they are automatically covered by tests. It is also true for private methods as they are usually the result of refactoring on the public/protected ones.


Share your comment

Jeff Langr

About the Author

Jeff Langr has been building software for 40 years and writing about it heavily for 20. You can find out more about Jeff, learn from the many helpful articles and books he's written, or read one of his 1000+ combined blog (including Agile in a Flash) and public posts.