Tuesday, February 11, 2014

Detailed examples for test case writing


1.Fix the test names.  If you can only do one thing to improve a test, change the test method's name to say what it does.  Yes, it may be long sometimes -- but by this way you know exactly what it does.

2."Coverage as" is your friend.  Continuing #1, if you're not sure what a test does, run a junit "coverage as" on that one test.  Now you can see from the green/pink coloring just what parts of the original class or method are getting executed.  That will give you at least a clue as to what the test is doing, and thus how it should be named.

3.Don't confuse real objects and mock objects.  If you're mixing a bunch of "real" objects and EasyMock objects, make sure you can tell them apart.  Use names!  I like to name my EasyMock objects mockSomethingOrOther.  (And particularly where you're doing an 'expect' on a void method, you can't tell just by looking at the code what is real vs. what is mock).

4.DRY: group common expects.  If you have several tests with identical expect's, pull them into a service method -- and give it a name that says what you're doing!  If they are almost identical, you can still probably pull them into a service method with an argument or two.

5.Don't overuse Easymock Static mocks are still useful.  A "static mock" is just a regular (non-EasyMock) object that you build yourself, implementing the same interface as the 'real' object that you need as a dependency.  If you're writing lots of expects on an EasyMock object, or if you really need a mock to calculate something... then write your own mock.

6.Order the phases of your tests.  If you're using EasyMock, your tests should look something like this:
A) Set up your mocks
B) expect's ...
C) replay()
D) execute the method(s) under test (and save the results)
E) verify()    (Required if you have a replay()!)
F) assert
In particular, don't put your asserts between your replay() and verify().  There's a good chance you'll unintentionally invoke a mocked method. 

7.Don't mix EasyMock.createControl() and EasyMock.createMock().  It’s one of the mistakes that I used to do many times. Sometimes we create most of their mocks from a common "ctrl" EasyMock object... and then stir in one or two explicit EasyMock.createMock's.  We almost always forget to replay() or verify() those extra mocks.  Don't do it!  You will forget one.  Use ctrl for all of your mocks.

8.DRY: string constants  If you use a simple string constant in your mocks, expects, etc. more than once... pull it into a static, upper-case-named constant.  And make it meaningful!

9.DRY: boolean constants.  Don't pass 'true' or 'false' into your test methods, expect's, etc.  It's a magic number. Use (or make) an upper-case static final constant.  A 'true' by itself means nothing.  Say what it means!

10.@Ignore if you must.  If you must disable a test temporarily, use @Ignore -- don't comment out the @Test (or worse, the entire code of the test method).  And do add a comment about why the test is @Ignore'd!

11.Get rid of warnings.  Use control-shift-O to clean up your imports.  Remove warnings wherever possible.  If not possible, let Eclipse tell you what annotation to use to ignore the warning.  Don't leave "intentional" warnings just lying around.  If the "false positive" warnings are removed, the ones that are remaining may be real bugs!

12.Get rid of unused code.  If you don't need it to pass the test, delete it!  If you feel like you need it, then you haven't finished writing (rewriting) the test.

13.Don't "swallow" exceptions!  If you must catch an exception (and usually you don't need to, just let the exception happen and Junit will fail and print the stack trace), then make sure to call fail() or otherwise make it clear whether the test succeeded or failed!

14.EasyMock's IMocksControl is a good thing.  Use it, it will help make sure you don't "lose" any mocks that should be replay()'d.  However, if you find yourself using multiple IMocksControl's in the same test, you're probably making a mess.  Reorder the construction and use of your mocks so that you only need one IMocksControl.

15.Treat your mocks as if they were final.  If you've defined a mock in an @Before method, don't go redefining it elsewhere.  That's sloppy C-style "everything is a global variable" coding.  If you need new mocks, create them, and make them local/temporary variables.  Otherwise, it becomes really hard to tell, just by reading the code, which expects match up with which versions of your mock.

Just follow these and you will love writing tests.

“Writing clean code is what you must do in order to call yourself a professional. There is no reasonable excuse for doing anything less than your best.” - Robert C. Martin

No comments:

Post a Comment