编写单元测试时,我需要一些带有样本数据的对象。例如,假设我有一个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反序列化我的对象。有没有一种标准,有效的方法来做到这一点?
答案 0 :(得分:14)
一般来说,DTO只包含字段,没有需要模拟的逻辑。
我会用DTO作为自己的模拟。如果DTO中有逻辑,你可能想嘲笑,我会把逻辑移出DTO。
要创建DTO,我会在测试本身或外部文件中通过文本执行此操作。您可以使用JSon,但如果您不使用它,我将使用XMLEncoder / XMLDecoder。它不是很漂亮的XML,但内置它,所以你不需要额外的库。
如果可以,您可以从应用程序的日志中创建DTO,这样您就可以重新创建一个真实的场景。
答案 1 :(得分:2)
答案 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,然后根据需要覆盖它们。如果Foo
和Bar
很复杂,那么您也可以拥有这些测试构建器,因此您可以执行类似
MyDto expectedDto = aMyDto()
.withDefaults()
.withFoo(aFoo()
.withName("testFoo"))
.build();
Freeman和Pryce撰写的以测试为导向的面向对象软件一书详细介绍了这一点。
您应该注意区分测试构建器,它们构建预先填充了合理的测试数据的对象,以及用于非测试代码的构建器(它是实例化不可变对象的常用模式)。不要跨这些流 - 不要在非测试代码中使用测试构建器。
答案 3 :(得分:1)
对于具有不同值的多个对象,我会选择Peter Lawreys的建议,但对于总是具有相同值的单个DTO,我将创建一个总是返回相同值的模拟。