简体   繁体   English

Hamcrest - 测试具有相同属性值的复杂对象的优雅方式

[英]Hamcrest - Elegant way to test complex object with samepropertyvaluesas

I have quite complex object structure (with bunch of primitive fields and object references) and want to test all fields except -a few- of them.我有相当复杂的对象结构(有一堆原始字段和对象引用),并且想要测试除 - 少数 - 之外的所有字段。 As an example;举个例子;

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

Since I don't want to check all fields manually, I believe there must be a way to write that test elegantly.由于我不想手动检查所有字段,因此我相信必须有一种方法可以优雅地编写该测试。 Any ideas?有任何想法吗?

Cheers.干杯。

You should have a look at shazamcrest , a great Hamcrest extension that offers what you need.你应该看看shazamcrest ,这是一个很棒的Hamcrest扩展,可以提供你需要的东西。

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

See https://github.com/shazam/shazamcrest#ignoring-fieldshttps://github.com/shazam/shazamcrest#ignoring-fields

Just pass the list of properties to ignore as 2nd parameter to samePropertyValuesAs.只需将要忽略的属性列表作为第二个参数传递给 samePropertyValuesAs。

Hamcrest matcher API Hamcrest 匹配器 API

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

eg例如

samePropertyValuesAs(salesRecord,"id")

In general I see two solutions if ComplexObject can be modified by yourself.一般来说,如果ComplexObject可以自己修改,我会看到两种解决方案。

You could introduce an interface that represents the properties of ComplexObject that are being changed by ActualFunction .您可以引入一个接口来表示由ActualFunction更改的ComplexObject的属性。 Then you can test that all properties of that new interface have changed.然后,您可以测试该新界面的所有属性是否都已更改。 This would require that ComplexObject implements that new interface.这将要求ComplexObject实现该新接口。

Another approach would be to replace the properties of ComplextObject that are changed by ActualFunction with a new property of a new type that contains all those properties.另一种方法是更换的特性ComplextObject由改变ActualFunction一个新的类型,包含所有这些属性的新属性。 A better design would then be to let ActualFunction return an instance of the new type.更好的设计是让ActualFunction返回新类型的实例。

Last time I had a similar requirements I came to the conclusion that manually writing both code and tests to assert that some values are updated is inherently fagile and error-prone.上次我有类似的要求时,我得出的结论是,手动编写代码和测试来断言某些值已更新本质上是脆弱且容易出错的。

I externalized the fields in a bag object and generated the Java source files for both the bag class itself and the copier at compile time.我将 bag 对象中的字段外部化,并在编译时为 bag 类本身和复制器生成了 Java 源文件。 This way you can test actual code (the generator) and have the actual definition of the domain in exactly one place, so the copy code can't be out-of-date.通过这种方式,您可以测试实际代码(生成器)并将域的实际定义准确地放在一个地方,因此复制代码不会过时。

The language to describe the property can be anything you are comfortable with, from JSON-schema to XML to Java itself (Java example follows - custom annotations are to be consumed from the generator)描述属性的语言可以是任何你喜欢的语言,从 JSON 模式到 XML 再到 Java 本身(Java 示例如下 - 将从生成器中使用自定义注释)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM