简体   繁体   中英

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.

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

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

Just pass the list of properties to ignore as 2nd parameter to samePropertyValuesAs.

Hamcrest matcher 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.

You could introduce an interface that represents the properties of ComplexObject that are being changed by ActualFunction . Then you can test that all properties of that new interface have changed. This would require that ComplexObject implements that new interface.

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. A better design would then be to let ActualFunction return an instance of the new type.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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