TestDataCaptureJ – Capture data for your unit tests

When you are writing unit tests or doing Test Driven Development (TDD) , one of tasks you may need to do is to get some data to run your tests with. If the data that you need is fairly simple then there are various options, such as manually creating the data classes, create some mocks, stick some data in a database, etc.

However if you need a large amount of complex data, then these options can become very time consuming. This was the situation that I’ve come across myself in various projects, in particular where I need to test a the checkout stage in a online shop using data from the basket. The development environment was running on a snapshot of the production database (therefore ‘real’ data) and for the test scenarios I need the data from the shopping basket with various combinations of basket items. However the basket items were quite complex: the basket item class had about 35 fields, some of which were other objects each containing maybe 5 – 15 fields themselves.

To get all the test data I needed to test all the scenarios, I created a tool which evolved into the TestDataCaptureJ open source project that is hosted on GitHub. This is a Java development tool that can be used in java (web) applications to capture data as you run through the test scenarios. The data is logged to file, but in a format that you can just cut and paste into your unit tests (or better still, into classes that are used by your unit tests).

As an example, in the tutorial I used the jpetstore sample app from the Spring Framework. This just meant configuring the jpetstore web app to run with TestDataCaptureJ, and then going through the checkout process with some items in the basket. Then I used the generated log in some unit tests that I wrote to test part of the checkout process. This is an example of the code that was generated:

public org.springframework.samples.jpetstore.domain.Account createParam1Account_org_springframework_samples_jpetstore_domain_Order_initOrder() {

org.springframework.samples.jpetstore.domain.Account account0 = new org.springframework.samples.jpetstore.domain.Account();
account0.setUsername("j2ee");
account0.setPassword(null);
account0.setEmail("yourname@yourdomain.com");
account0.setFirstName("ABC");
account0.setLastName("XYX");
account0.setStatus("OK");
account0.setAddress1("901 San Antonio Road");
account0.setAddress2("MS UCUP02-206");
account0.setCity("Palo Alto");
account0.setState("CA");
account0.setZip("94303");
account0.setCountry("USA");
account0.setPhone("555-555-5555");
account0.setFavouriteCategoryId("DOGS");
account0.setLanguagePreference("english");
account0.setListOption(true);
account0.setBannerOption(true);
account0.setBannerName("");

return account0;
}

The tutorial also demonstrates some of the limitations of the tool as well.

Caveats

TestDataCaptureJ was really meant to handle data objects which are designed to hold data and follow JavaBean conventions, e.g.

  • objects are created using constructors
  • fields has setter methods using standard naming convention
    e.g. a field named ‘userAccountName’ would have a public setter method ‘setUserAccountName()’

Also to intercept the processing of the application in order to log the data, the test data required must be an object that is either passed to a method as a parameter, or returned from a method as a return value.

Therefore it can’t currently handle object where this isn’t the case, e.g.

  • object that are not created with constructors, e.g. if they are created using factory methods instead
  • fields without setter methods or setter methods that don’t follow the standard naming convention
  • static fields (just not implemented)
  • objects pass into methods as varargs

There is some configuration that

How it works

Basically this is just a glorified version of the common AspectJ tracing example, using weave time loading to intercept the data objects that we are interested in. Only instead of just logging the contents, there is a 2 stage process:

  1. use java reflection to store access the field data recursively and store it in some metadata classes
  2. log the data as java code to file

There is a explanation page in the documentation that goes into more detail.

Please have a look at the code (or better still, fork it and play around with it) or read the documentation if you think this might be useful to you.