Inspired by lot of dummy work to create matchers for fields in auto-generated beans to write POJO-based tests.
Generates Hamcrest's Feature Matchers
for every field annotated with @GenerateMatcher
annotation (ru.yandex.qatools.processors.matcher.gen.annotations.GenerateMatcher
).
Useful for testing auto-generated unmarshalled beans with help of jsonschema2pojo + Gson or JAXB
<dependency>
<groupId>ru.yandex.qatools.processors</groupId>
<artifactId>feature-matcher-generator</artifactId>
<version>2.0.0</version>
<!-- 'provided' scope because this is only needed during compilation -->
<scope>provided</scope>
</dependency>
@GenerateMatcher // works with class level annotations as every field with same annotation
public class Owner {
@GenerateMatcher
private String email;
@GenerateMatcher
private String uid;
@DoNotGenerateMatcher // excludes field from generation of matchers for class level @GenerateMatcher annotation
private String name;
public String getEmail() {
return email;
}
public String getUid() {
return uid;
}
}
Beans MUST
have getters with named get[Field]()
to generate working matchers
Run mvn clean compile
Also:
matcher.gen.annotations
. For example we have @Expose
annotation (com.google.gson.annotations.Expose
) by Gson
and want to generate matchers for fields with such annotation.
mvn clean compile -Dmatcher.gen.annotations=ru.yandex.qatools.processors.matcher.gen.annotations.GenerateMatcher,com.google.gson.annotations.Expose
matchers.gen.properties
with content
matcher.gen.annotations=ru.yandex.qatools.processors.matcher.gen.annotations.GenerateMatcher,com.google.gson.annotations.Expose
You can find result in ${project.build.directory}/generated-sources/annotations/*
.
For each class with such fields will be generated class *Matchers
with public static methods looks like:
/**
* Matcher for {@link ru.yandex.qatools.beans.Owner#email}
*/
@org.hamcrest.Factory
public static org.hamcrest.Matcher<ru.yandex.qatools.beans.Owner> withEmail(org.hamcrest.Matcher<java.lang.String> matcher) {
return new org.hamcrest.FeatureMatcher<ru.yandex.qatools.beans.Owner, java.lang.String>(matcher, "email", "email") {
@Override
protected java.lang.String featureValueOf(ru.yandex.qatools.beans.Owner actual) {
return actual.getEmail();
}
};
}
assertThat(someOwner, withEmail(containsString("@")));
// OR combined:
assertThat(someOwner, both(withEmail(containsString("@"))).and(withUid(is(uid)));
There are 2 ways:
test
scopeAdd one more execution for maven-jaxb2-plugin
:
<execution>
<id>test</id>
<phase>process-test-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<generateDirectory>target/generated-test-sources/xjc</generateDirectory>
<addCompileSourceRoot>false</addCompileSourceRoot>
<addTestCompileSourceRoot>true</addTestCompileSourceRoot>
<args>
<!--bunch of plugins that can be different from original configuration-->
<arg>-enableIntrospection</arg>
<arg>-no-header</arg>
<arg>-Xxew</arg>
<arg>-Xxew:instantiate lazy</arg>
<arg>-Xfluent-api</arg>
<arg>-Xinheritance</arg>
<arg>-Xannotate</arg>
<arg>-Xvalue-constructor</arg>
<arg>-Xequals</arg> <!--in tests it will be useful to have to strings, equals...-->
<arg>-XhashCode</arg>
<arg>-XtoString</arg>
</args>
</configuration>
</execution>
If you want to add toString
, equals
etc methods, don't forget to add also dependency to test scope:
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<scope>test</scope>
</dependency>
Add dependency to annotaion processor to <scope>test</scope>
Add matchers.gen.properties
file to src/test/resources/
with content:
matcher.gen.annotations=javax.xml.bind.annotation.XmlElement
export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
mvn clean compile
"Maven Projects"
view"Yandex QATools Annotation Processors"
element"package"
"Debug 'annotation-processors'"
It will create a new launcher configuration which can be used to debug project.
Not supported: EmptyClass -> EmptyStaticNested -> StaticNestedWithFields