【问题标题】:What is the best way to mock DTOs in Java?在 Java 中模拟 DTO 的最佳方法是什么?
【发布时间】:2012-09-17 07:31:26
【问题描述】:
在编写单元测试时,我需要一些带有示例数据的对象。例如,假设我有一个 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 反序列化我的对象。有没有标准、有效的方法来做到这一点?
【问题讨论】:
标签:
java
unit-testing
mocking
dto
【解决方案1】:
通常 DTO 只包含字段,没有需要模拟的逻辑。
我会使用 DTO 作为其自身的模拟。如果 DTO 中包含您可能想模拟的逻辑,我会将逻辑移出 DTO。
要创建 DTO,我会从文本中执行此操作,无论是在测试本身中,还是从外部文件中。您可以使用 JSON,但如果您不使用它,我将使用 XMLEncoder/XMLDecoder。它不是漂亮的 XML,但它是内置的,因此您不需要额外的库。
如果可以,您或许可以从应用程序的日志中创建 DTO,这样您就可以重新创建一个真实的场景。
【解决方案2】:
另一种方法可能是为属性生成随机值。
PODAM 或 openpojo 之类的实用程序可以提供帮助。
我会尽量混合使用这两种方法。比如——用PODAM生成对象,然后手动设置不能随机的值。
【解决方案3】:
模拟框架通常不鼓励模拟数据对象。
但是每次在测试中需要数据对象时填充数据对象可能会很不方便。
一种常见的方法是使用测试构建器。比如:
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一书中详细介绍了这一点。
您应该注意区分测试构建器和用于非测试代码的构建器(这是实例化不可变对象的常见模式)。不要跨越这些流——不要在非测试代码中使用您的测试构建器。
【解决方案4】:
对于具有不同值的多个对象,我会采用 Peter Lawreys 的建议,但对于始终具有相同值的单个 DTO,我会创建一个始终返回相同值的模拟。