12

When writing unit tests I need some objects with sample data. For example suppose I have an Order object. One needs to write code like this -

Order o = new Order();
o.setId(3);
o.setAmount(2830.9);

List<Item> items = new ArrayList<Item>();
Item i = new Item();
i.setId(3);
i.setCost(34);
items.add(i);

o.setItems(items);

It is a lot more frustrating and redundant than it looks here because a real object is likely to have lot more attributes and nested objects.

And if one needs multiple orders ...

What is the best way to create mock data objects for testing?

Off the top of my head I'm thinking about deserializing my objects from Json. Is there a standard, efficient way to do this?

EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
Kshitiz Sharma
  • 17,947
  • 26
  • 98
  • 169

4 Answers4

17

Generally DTO contain only fields and no logic which needs to be mocked out.

I would use a DTO as a mock of itself. If the DTO has logic in it you might like to mock out, I would move the logic out of the DTO.

To create DTO, I would do this from text, either in the test itself, or from an external file. You could use JSon, but if you don't use that already I would use XMLEncoder/XMLDecoder. Its not pretty XML but it is built in so you don't need an extra library.

If you can, you might be able to create DTOs from the logs of the application, so you can recreate a realistic scenario.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
4

Another approach might be to generate random values for the attributes.

A utility like PODAM or openpojo can help.

I'll try to mix the two approaches as appropriate. For example - generate the object with PODAM and then manually set the values that can't be random.

Kshitiz Sharma
  • 17,947
  • 26
  • 98
  • 169
3

Mocking frameworks generally discourage mocking data objects.

But it can be inconvenient to populate a data object every time you need it in a test.

A common approach is to use a test builder. Something like:

public class MyDtoBuilder {

   private Foo foo;
   private Bar bar;

   public static MyDtoBuilder aMyDto() {
       return new MyDtoBuilder();
   }

   public MyDtoBuilder withFoo(Foo foo) {
       this.foo = foo;
       return this;
   }

   public MyDtoBuilder withBar(Bar bar) {
       this.bar = bar;
       return this;
   }

   public MyDtoBuilder withDefaults() {
       return this.withFoo(new Foo(...)).withBar(new Bar(...));
   }

   public MyDto build() {
       return new MyDto(foo,bar);
   }
}

Now you can conveniently build a DTO with default values, then override them as required. If Foo and Bar are complex, you can have test builders for these too, so you can do stuff like

  MyDto expectedDto = aMyDto()
      .withDefaults()
      .withFoo(aFoo()
          .withName("testFoo"))
      .build();

This is covered in detail in the book Growing Object-Oriented Software Guided by Tests by Freeman and Pryce.

You should take care to distinguish between test builders, which build objects pre-filled with plausible test data, and builders intended for non-test code (it's a common pattern for instantiating immutable objects). Don't cross these streams -- don't use your test builders in non-test code.

slim
  • 40,215
  • 13
  • 94
  • 127
1

For multiple objects with different values I would go with Peter Lawreys suggestion, but for a single DTO with always the same value I would create a mock that always returns the same values.

EricSchaefer
  • 25,272
  • 21
  • 67
  • 103