在Java中模拟DTO的最佳方法是什么?

时间:2012-09-17 07:31:27

标签: java unit-testing mocking dto

编写单元测试时,我需要一些带有样本数据的对象。例如,假设我有一个Order对象。人们需要编写这样的代码 -

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);

这比看起来更令人沮丧和多余,因为真实对象可能有更多属性和嵌套对象。

如果需要多个订单......

创建模拟数据对象以进行测试的最佳方法是什么?

我正在考虑从Json反序列化我的对象。有没有一种标准,有效的方法来做到这一点?

4 个答案:

答案 0 :(得分:14)

一般来说,DTO只包含字段,没有需要模拟的逻辑。

我会用DTO作为自己的模拟。如果DTO中有逻辑,你可能想嘲笑,我会把逻辑移出DTO。

要创建DTO,我会在测试本身或外部文件中通过文本执行此操作。您可以使用JSon,但如果您不使用它,我将使用XMLEncoder / XMLDecoder。它不是很漂亮的XML,但内置它,所以你不需要额外的库。

如果可以,您可以从应用程序的日志中创建DTO,这样您就可以重新创建一个真实的场景。

答案 1 :(得分:2)

另一种方法可能是为属性生成随机值。

PODAMopenpojo等实用程序可以提供帮助。

我会尽量混合使用这两种方法。例如 - 使用PODAM生成对象,然后手动设置不能随机的值。

答案 2 :(得分:2)

模拟框架通常不鼓励模拟数据对象。

但是每次在测试中需要时填充数据对象可能会很不方便。

常用方法是使用测试构建器。类似的东西:

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);
   }
}

现在,您可以方便地使用默认值构建DTO,然后根据需要覆盖它们。如果FooBar很复杂,那么您也可以拥有这些测试构建器,因此您可以执行类似

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

Freeman和Pryce撰写的以测试为导向的面向对象软件一书详细介绍了这一点。

您应该注意区分测试构建器,它们构建预先填充了合理的测试数据的对象,以及用于非测试代码的构建器(它是实例化不可变对象的常用模式)。不要跨这些流 - 不要在非测试代码中使用测试构建器。

答案 3 :(得分:1)

对于具有不同值的多个对象,我会选择Peter Lawreys的建议,但对于总是具有相同值的单个DTO,我将创建一个总是返回相同值的模拟。