Hamcrest - 使用相同的属性值来测试复杂对象的优雅方法

时间:2016-02-26 10:47:19

标签: java junit hamcrest

我有相当复杂的对象结构(有一堆原始字段和对象引用),并且想要测试除了少数几个字段之外的所有字段。作为一个例子;

ComplexObject actual = generateMagically("someInput");
ComplexObject expected = ActualFunction.instance.workMagically(actual);

// we want to be sure that workMagically() would create a new ComplexObject
// with some fields are different than "actual" object.

// assertThat(actual, samePropertyValuesAs(expected)); would check all fields.
// what I want is actually; - notice that "fieldName1" and "fieldName2" are 
// primitives belong to ComplexObject
assertThat(actual, samePropertyValuesExceptAs(expected, "fieldName1", "fieldName2"))

由于我不想手动检查所有字段,我相信必须有办法优雅地编写该测试。有什么想法吗?

干杯。

4 个答案:

答案 0 :(得分:9)

您应该查看shazamcrest,这是一个很棒的Hamcrest扩展程序,可以提供您所需要的内容。

assertThat(expected, sameBeanAs(expectedPerson).ignoring("fieldName1").ignoring("fieldName2"));

请参阅https://github.com/shazam/shazamcrest#ignoring-fields

答案 1 :(得分:1)

只需将要忽略的属性列表作为第二个参数传递给samePropertyValuesAs。

Hamcrest Matcher API

public static <B> Matcher<B> samePropertyValuesAs(B expectedBean, String... ignoredProperties)

例如

samePropertyValuesAs(salesRecord,"id")

答案 2 :(得分:0)

一般情况下,如果ComplexObject可以自行修改,我会看到两种解决方案。

您可以引入一个界面来表示ComplexObject正在更改ActualFunction的属性。然后,您可以测试该新接口的所有属性是否已更改。这将要求ComplexObject实现新接口。

另一种方法是使用包含所有这些属性的新类型的新属性替换ComplextObject更改的ActualFunction属性。然后,更好的设计是让ActualFunction返回新类型的实例。

答案 3 :(得分:0)

上次我有类似的要求时,我得出的结论是,手动编写代码和测试来断言某些值被更新本身就是错误的,容易出错。

我将bag对象中的字段外部化,并在编译时为bag类本身和复制器生成Java源文件。通过这种方式,您可以测试实际代码(生成器)并在一个位置具有域的实际定义,因此复制代码不能过时。

描述属性的语言可以是您熟悉的任何语言,从JSON模式到XML到Java本身(Java示例如下 - 自定义注释将从生成器中使用)

public class MyBag {
  @Prop public int oh;
  @Prop public String yeah;
}