Jean-Baptiste is a French software engineer since 2007. He loves great user experience, simple and robust architectures, and solid tests. He blogs about good development and team practices, business and Korea (his wife's country). Always willing to learn from others and connect with fellow engineers from other countries. Jean-baptiste is a DZone MVB and is not an employee of DZone and has posted 1 posts at DZone. You can read more from them at their website. View Full User Profile

Good Unit Test CheckList

08.19.2011
| 7728 views |
  • submit to reddit

Here are a few items I try to respect every time I write unit tests.

  • My test class is testing one and only one class
  • My methods are testing one and only one method at a time
  • My variables and methods names are explicit
  • My test cases are easy to read by human
  • My tests are also testing expected exception with @Test(expected=MyException.class)
  • My tests don’t need access to database
  • My tests don’t need access to network resources
  • My tests respect the usual clean code standards (lenght of lines, cyclomatic complexity,…)
  • My tests control side effects, limit values (max, min) and null variables (even if it throws an exception)
  • My tests can be run any time on any place without needing configuration
  • My tests are concrete (ex. dates are hardwired, not computed every time, strings too…)
  • My tests use mock to simulate/stub complex class structure or methods
I’m pretty sure there are more.  Any ideas?

From http://jbrieu.info/leblog/2011/good-unit-test-checklist/

Published at DZone with permission of Jean-baptiste Rieu, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Tom Gardner replied on Sat, 2011/08/20 - 3:28am

Most of your points are good and valuable, but...

It is very rare to be able to only test one class at a time: in the vast majority of the cases you are testing the integration of your class with one or more libraries. Just look and see whether your unit-under-test has any import statements! If you think libraries are error-free, then I have a bridge I'd like to sell you :)

Testing only one method at a time is, of itself, not a benefit. I have frequently seen this principle used to justify  reducing the quality of the unit-under-test. For example, unnecessarily making getter/setter methods public solely so they can be unit tested.

Liam Knox replied on Sun, 2011/08/21 - 7:01am

Its a fair list but I think too purist as a whole. Unless you want differentiate Unit and some other forms of automated testing you will find the automated tests will cover DAOs and for good reason, i.e. exercising stored procedures and transactional semantics.

Configuration is also contentious. Spring has great support for this which often is easier to use and covers more that trying to use pure programmatic idioms and mocks.

And probably the most contentious of all is the one 2 one method. I doubt you will ever find this is followed 100% in any large team. I don't think its a good rule. If you express tests that cover business scenarios that exercise many classes/methods these often have more meaning and more proveable coverage and correctness.

Chad Hahn replied on Sun, 2011/08/21 - 7:26am in response to: Tom Gardner

It is very rare to be able to only test one class at a time: in the vast majority of the cases you are testing the integration of your class with one or more libraries. Just look and see whether your unit-under-test has any import statements!

This is really where DI comes into play. When you inject the needed dependencies into a class, you're free to use mocks or stubs to NOT test the libraries. That's what unit testing is, testing things in isolation. If you want to test the interaction between other classes and libraries, you'd want to do integration testing.
Testing only one method at a time is, of itself, not a benefit. I have frequently seen this principle used to justify reducing the quality of the unit-under-test. For example, unnecessarily making getter/setter methods public solely so they can be unit tested.

It's somewhat common to increase scope in order to satisfy testing, but you would never go from private to public. You'd go from private to friendly. However, if you're doing it correctly, your private methods should be tested in the course of testing the public interface, otherwise the private methods aren't being used.

Tom Gardner replied on Sun, 2011/08/21 - 11:45am in response to: Liam Knox

"If you express tests that cover business scenarios that exercise many classes/methods these often have more meaning and more proveable coverage and correctness."

Precisely.

As I wish more people realised, there has to be a stated reason for doing a test. If there isn't, then the testing is just a fetish that is being used to ward off Unspecified Bad Things

Tom Gardner replied on Sun, 2011/08/21 - 11:55am in response to: Chad Hahn

"This is really where DI comes into play. When you inject the needed dependencies into a class, you're free to use mocks or stubs to NOT test the libraries. That's what unit testing is, testing things in isolation. If you want to test the interaction between other classes and libraries, you'd want to do integration testing."

  1. Do you really use DI to mock the standard library? Or any other non-standard but widely-used library? If so, what benefit do you get from it?
  2. Who cares whether your class/method works with other classes/methods written by you? Your class/method and the library class/method may each be correct in isolation but faulty when used together. Or it is quite possible that your mock exhibits significantly different behaviour to the "real" library.
Yes, that does mean that either almost all non-trivial testing is integration testing, or that "unit" has to be defined to be larger than a single class.

Tom Gardner replied on Sun, 2011/08/21 - 12:03pm in response to: Chad Hahn

"It's somewhat common to increase scope in order to satisfy testing, but you would never go from private to public. You'd go from private to friendly. However, if you're doing it correctly, your private methods should be tested in the course of testing the public interface, otherwise the private methods aren't being used."

I've seen it done, repeatedly. Sorry, I can't fix the world by removing all bad developers.

Black boxes are better than transparent boxes because you know you don't have to understand how they work.

Private methods are not part of the public interface/signature that has to be maintained/preserved as the software evolves, whereas public and friendly methods (and classes) are. Hence making something unnecessarily non-private reduces the software quality by:

  • increasing the number of things that a client programmer has to understand and decide to ignore
  • increasing the maintenance burden
  • increasing the probability that someone in the future will make a Bad Choice

 

Chad Hahn replied on Sun, 2011/08/21 - 1:59pm in response to: Tom Gardner

Who cares whether your class/method works with other classes/methods written by you? Your class/method and the library class/method may each be correct in isolation but faulty when used together.

I think it would be helpful to get yourself a copy of JUnit in Action or a similar book and read it carefully. It'll give you a better understanding of what a unit test is, why they are important, and why testing in isolation is a goal to strive for.

Heck, grab yourself a copy of Pragmatic Unit Testing by Hunt and Thomas from 2003. They had it correct back then when they wrote "A unit test is a piece of code written by a developer that exercises a very small, specific area of functionality of the code being tested." They go on to explain mocking, independent tests (isolation), and some pitfalls around improper testing.

This isn't rocket surgery, but, among the teams I've worked with, it's surprising how immature some of them have been when it comes to proper testing. I think that's because people refuse to acknowledge the body of work already done in this area. We really shouldn't have to be spending time trying to redefine "unit" as "larger than a single class" testing.

Tom Gardner replied on Mon, 2011/08/22 - 4:52pm

You have ignored the point I was making and "answered" (and I use that word loosely) with a diatribe.

 I've been using JUnit (and TestNG) for the past decade and have introduced its use to more than one company, so I'm well aware of its advantages. And also of the limitations to unit testing.

Having developed systems where

  • a single mistake costs 8 years' salary and three to six months elapased time to fix, and
  • even if the machine operates according to its design specification, it could kill someone

I am well aware that unit testing is limited.

There's an old engineering aphorism: "you can't inspect or test quality into a product". I suggest you ponder the wisdom in that truism

Chad Hahn replied on Mon, 2011/08/22 - 10:14pm in response to: Tom Gardner

I was trying to point out that you're basing your argument on a principle that is generally considered wrong. You said "It is very rare to be able to only test one class at a time." That statement goes against what is commonly accepted as unit testing. If you want to complain about the OP, you need to understand the terms he's using. Nothing more, nothing less.

Tom Gardner replied on Tue, 2011/08/23 - 2:07am

I suggest you read what I actually wrote in its entirety, and not base your point on a partial quote. I'll try to spell it out.

How many of your classes don't have a single import statement? If they have one or more import statements then you aren't testing a single class in isolation: you are testing one class and its integration with the classes named in the import statements. It really is that simple.

Yes, that does mean that the whole concept of "test one class on its own" is so simplistic as to be misleading. 

It doesn't mean that "unit testing" is a misnomer,  merely that the "unit" is almost always larger than a single class, and should be recognised as such.

Chad Hahn replied on Tue, 2011/08/23 - 7:03am in response to: Tom Gardner

If I have two classes, A, B and A takes B as a dependency in its constructor. If I were to unit test class A, I wouldn't give it a real class B. Why not? Because I want to test class A in isolation. Perhaps B isn't even implemented yet and all I have is an interface. Now I have a nice set of test for class A and I'm free to refactor and improve it as needed while still keeping the tests passing. Import statements don't imply tight coupling.

Andrew Spencer replied on Tue, 2011/08/23 - 7:50am

Tom,a decade ago it would have been reasonable to argue that you can't test a class in isolation. But these days, at least in my field, developers are expected to know how avoid hardwiring dependencies.

I totally agree that testing a class in isolation isn't enough - even in the non critical systems I develop - and that you also need to test how classes interact. I call that integration testing, though the term's too broad and I'd be happy to accept a more precise taxonomy.

There's a danger here of confusion between a discussion about what kinds testing one should do, with a discussion about what one means by a term such as unit testing. This has led previous commenters to talk at cross purposes. Stating that unit testing means testing only one class at a time, is not the same as arguing that integration tests are superfluous. Are you certain you're not tilting at windmills?

Tom Gardner replied on Thu, 2011/08/25 - 4:24am

Thank you, Andrew, for a thoughtful post. My principal argument is with those people that make statements that are so wideranging that they become wrong - even though the statements were inspired by valid principles. (That's why the GoF Design Patterns book containd the "do not use if..." sections explaining when a design pattern shouldn't be used)

Hardwiring dependencies is an interesting topic, and I suspect our views are actually closely aligned in this area. There are many cases in which removing a dependency that has been lazily, unnecessarily and harmfully introduced is clearly The Right Thing To Do. And, unfortunately I've had to spend too much of my professional lifeteaching and mentoring people in such techniques.

However, I'm sure you'd agree that it is impractical and not beneficial to remove all dependencies. Obvious examples of the former: the standard String, Set, Integer classes. Obvious examples of the latter would be trying to remove a dependency on, say, ThreadedExecutor or BoundedBuffer in which the correctness of your class relies on the properties of those specific library classes and not their relatives.

I've also seen people take generally useful rules of thumb and relentlessly apply them without understanding when they aren't beneficial. Such religious cargo-cult application of techniques is intensely annoying.

As you imply, the boundary between unit testing and integration testing is a gray area. Some poster's comments don't indicate that they realise that.

As for "tilting at windmills"? Certainly not :) Because, unlike Don Quixote, I'm right.

Tom Gardner replied on Thu, 2011/08/25 - 4:20am

Chris, your points, while they have some academic merit, are so wideranging as to be invalid in many real-world contexts. 

For example, if my class's correctness is predicated on its using a DirectExecutor rather than a ThreadedExecutor, then it would simply be bad engineering to allow the possibility of accepting a ThreadedExecutor in my classes' constructor. And attempting to test my class without using the DirectExecutor would be merely an exercise in intellectual onanism.

I agree that "import statements don't imply tight coupling". But they do imply coupling, and that is all that is needed to destroy the concept that is it possible/practical/beneficial to test such a class on its own.

As for refactoring: in me experience I've rarely seen it possible to refactor a single class onits own - except when I've been merely tweaking a business rule of some sort that is dropped into a framework. Almost always refactoring involves changing a set of highly cohesive classes.

There's good evidence that is the normal case for everybody else: the way refactoring editors/IDEs track inter-class dependencies. And the converse is true: if it wasn't the case then it would be easy and sufficient to use traditional editors in the old-fashioned way e.g. emacs + grep.

Chad Hahn replied on Thu, 2011/08/25 - 8:46am

Ted, You might enjoy this article on unit testing (not integration testing or validation testing or any other testing, just straight unit testing) which popped up here today. There isn't anything "wideranging" about it. Sometimes people just have problems understand concepts they are unfamiliar with. It happens to everyone. Unit Testing for Java EE

Tom Gardner replied on Fri, 2011/08/26 - 2:00am

If by "Ted" you mean me then I am well aware that, within the limited subset of coding exemplified by JEE (or JAIN etc), unit testing is practical and beneficial. I alluded to that when I wrote "...except when I've been merely tweaking a business rule of some sort that is dropped into a framework". Maybe I shouhld have been more specific.

But that is a very limited set of programming envionments and conditions, as I alluded to when I mentioned some of concurrency classes that you would never use inside a JEE component. If your professional activity is limited to such environments I can understand your attitude to unit programming.

However, programming is much more wideranging and varied than "inside" JEE/JAIN/etc environments - obvious examples being real-time programming (where being 1ms too late with the "correct" answer means that answer is actually wrong) or high performance computing (where heat dissipation, the speed of light and buggy compilers/languages (e.g. C/C++) limit your ability to get an answer within a useful timeframe).

Hence your statements about unit testing are too wideranging. There's a lot you haven't experienced- don't presume that your limited experience is universally applicable.

Sorry for adding the emphasis, but it looks like you've been skimming what I wrote without thinking about it.

Chad Hahn replied on Thu, 2011/10/27 - 6:10pm in response to: Tom Gardner

Well, Ted, now you've just got into the realm of crazy and you know it. We're speaking about the most common scenarios, which is what you'll experience 99% of the time. Now, I'll thank you to grow up and give up your petty personal attacks as you're clearly in the wrong on this one.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.