Monday, July 2, 2007

Unit testing setters and getters

So here's a question for the masses: is it worth it to unit test simple setters and getters? I would contend that if you can automatically generate the code for them, you can also automatically generate the unit test code that tests them (I smell a new ELisp command coming...). So what code should this tool actually generate? Here's my first cut, assuming we're going to use EasyMock: Let's say the name of the bean is foo, and it has class Foo (we'll go into unit testing beans of base type in a later post). Also, let's assume that the code for this in the production class (to distinguish it from the unit test class) looks as follows:

public class Production {
  protected Foo foo;
  public void setFoo(Foo foo) { this.foo = foo; }
  public Foo getFoo() { return this.foo; }
}
Note here that we made the foo field have protected scope, so that our test class (which we are assuming will be in the same package) can access it directly. I claim that these are the tests we need to write:
public class TestProduction extends TestCase {
  protected Foo mockFoo;
  private Production underTest;
  public void setUp() {
    mockFoo = EasyMock.createMock(Foo.class);
    underTest = new Production();
  }
  private void replayMocks() {
    EasyMock.replay(mockFoo);
  }
  private void verifyMocks() {
    EasyMock.verify(mockFoo);
  }
  public testSetsOwnFooForSetFoo() {
    replayMocks();
    underTest.setFoo(mockFoo);
    verifyMocks();
    assertSame(mockFoo, underTest.foo);
  }
  public testReturnsOwnFooForGetFoo() {
    underTest.foo = mockFoo;
    replayMocks();
    Foo result = underTest.getFoo();
    verifyMocks();
    assertSame(mockFoo, result);
  }
}
The replayMocks and verifyMocks are a habit I've developed, where I actually replay and verify all the mock objects in the test class, just to make sure I don't forget any. The use of these methods for these particular test cases actually asserts that there's no funny business going on here; none of the collaborators for the Production class are being called. So are there any cases this misses? What else would you want to test on your setters and getters? Tomorrow: what to do about base types.

4 comments:

Tatsu said...

It's funny, I've been writing documentation for my company on unit testing, so here's what I wrote about why to test Javabeans:
- Conventions and coding practices may say not to put logic in your beans, but since you are not likely to be maintaining your code for its entire lifetime, you'll never be able to guarantee that somewhere down the line someone doesn't "break the rules" and misuse your code.
- You are trusting that a tool generated your code correctly.
- You can't claim full unit testing coverage if none of your beans are being tested.
- Because its ridiculously easy, so why wouldn't you?

There are plenty of ways to do it yourself, but the simplest thing I have found is a small open source utility from GTC group called TestUtil. It has some more robust features, but in its simplest form, your code looks like this:

public class SomeDataBeanTest extends TestCase {
public void testMutators() {
assertTrue("Getter/Setter test failed on: SomeDataBean.java", TestUtil.verifyMutable(new SomeDataBean()));
}
}

Jon said...

Interesting. Do you have a link to TestUtil? It looks like it probably uses reflection rather
than explicitly writing out the tests; I'd be happy to look into it and follow up with a proper blog post about it.

Anonymous said...

I'm guessing it's this one:

GTC group called TestUtil.

Anonymous said...

I'm guessing it's this one:

http://gtcgroup.com/util/index.html