9

在编写单元测试时,我需要一些带有示例数据的对象。例如,假设我有一个 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

4 回答 4

15

通常 DTO 只包含字段,没有需要模拟的逻辑。

我会使用 DTO 作为自己的模拟。如果 DTO 中包含您可能想模拟的逻辑,我会将逻辑移出 DTO。

要创建 DTO,我会从文本中执行此操作,无论是在测试本身中,还是从外部文件中。您可以使用 JSON,但如果您不使用它,我将使用 XMLEncoder/XMLDecoder。它不是漂亮的 XML,但它是内置的,因此您不需要额外的库。

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

于 2012-09-17T07:35:24.257 回答
4

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

PODAMopenpojo这样的实用程序可以提供帮助。

我将尝试适当地混合这两种方法。例如 - 使用 PODAM 生成对象,然后手动设置不能随机的值。

于 2012-09-17T08:09:55.520 回答
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,然后根据需要覆盖它们。如果Foo并且Bar很复杂,您也可以为这些测试构建器,因此您可以执行类似的操作

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

这在Freeman 和 Pryce的《 Growing Object-Oriented Software》一书中详细介绍了测试指导。

您应该注意区分测试构建器和用于非测试代码的构建器(这是实例化不可变对象的常见模式)。不要跨越这些流——不要在非测试代码中使用您的测试构建器。

于 2017-07-27T16:31:38.850 回答
1

对于具有不同值的多个对象,我会采用 Peter Lawreys 的建议,但对于始终具有相同值的单个 DTO,我将创建一个始终返回相同值的模拟。

于 2012-09-17T08:11:01.073 回答