Tuesday, April 7, 2015

Making Bean Unit Testing Less Monotonous

Unit testing ordinary beans like value objects, transfer objects, or entities is the most boring coding one can be subjected to.  Yes, it's easy, but it’s extremely monotonous.  

The unit testing for beans like this do have value, but it’s limited.  If you're manually coding tests of accessors and mutators, you can make an argument that the benefit might not be worth the labor cost.  I've taken a different approach: let’s reduce the cost.  Delegate monotonous coding to a utility and only takes one line of code per bean in most cases.  At one line per bean, the cost is definitely worth the benefit.  This idea led me to create BeanTester

BeanTester gets this testing down to one line in most cases.  It works on reflection, not code generation, so tests automatically adapts to changes in your beans.  In addition to testing properties, it performs several other standard tests.  Here's the list:

  • All accessors (e.g. getXXX() methods) execute without exception
  • All mutators (e.g. setXXX() methods) execute without exception
  • accessors return the value assigned to them via their corresponding mutator (e.g. getXXX() returns the same value submitted with setXXX())
  • An instance equals() itself
  • hashcode() runs without exception
  • hashcode() for an instance is constant over time if no changes are made to it
  • hashcode() equals 0. The pit test product plugs 0 in to determine if you're properly testing hashcode()
  • clone() executes without exception (if Clonable is implemented)
  • clone() equals the instance from which it was produced
  • compareTo() executes without exception
  • toString() executes without exception
  • toString() is not null. The pit test product plugs null in to determine if you're properly testing
  • An instance compareTo() is 0 when compared to itself
  • An instance serializes and equals a reconstituted version of itself (if java.io.Serializable is implemented)


Benefits to a utility besides code reduction are numerous:

  • The test changes automatically as your beans do.
  • Some tests (i.e. Serialization) are often omitted with manually written tests.
  • Code is easy to use and a lot easier to understand.
  • Test framework independence; will work in Junit or any other Java testing framework.
  • No changes to production code needed to use
  • Published via maven for easy project incorporation

Here are a few usage examples.  The most simple example with default behavior:
BeanTester beanTester = new BeanTester();
beanTester.testBean(PerformanceSummaryVO.class);  

Beans without null constructors can easily be tested, but you must provide construction arguments.

BeanTester beanTester = new BeanTester();
beanTester.testBean(PerformanceSummaryVO.class);

Fields can optionally be excluded.

beanTester.addExcludedField("firstOccuranceDt");

Custom values can easily be added for property testing:

beanTester.addTestValues(PerformanceSummaryVO.class, new Object[]{custom1, custom2});

Please give BeanTester a field test (instructions and download here).  If you have trouble with the product, please let me know about it.

1 comment:

  1. Hello, I have been using this to test POJO which has lambok annotations such as @Data and @Accessors but when sonar publishes results because uncovered conditions it does not have 100% coverage and i see its only 15%..am i missing anything here?

    ReplyDelete