Hamcrest Feature Matcher Generator for POJOs
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
Usage Guide
1. Add dependency from Maven Central
<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>
2. Generate (or write) beans
@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
3. Compile
Run mvn clean compile
Also:
- Can use any other annotation to process if override system property
matcher.gen.annotations
. - Can use multiply annotations comma-separated.
For example we have @Expose
annotation ( com.google.gson.annotations.Expose
) by Gson and want to generate matchers for fields with such annotation.
- Run compilation with
mvn clean compile -Dmatcher.gen.annotations=ru.yandex.qatools.processors.matcher.gen.annotations.GenerateMatcher,com.google.gson.annotations.Expose
- Or put in classpath
matchers.gen.properties
with content
matcher.gen.annotations=ru.yandex.qatools.processors.matcher.gen.annotations.GenerateMatcher,com.google.gson.annotations.Expose
4. See generated matchers
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();
}
}
;
}
5. Use it in your tests!
assertThat(someOwner, withEmail(containsString("@")));
// OR combined: assertThat(someOwner, both(withEmail(containsString("@"))).and(withUid(is(uid)));
How to produce matchers in test scope for JAXB generated classes
There are 2 ways:
- Generate as usually in separate module and just add as dependency in
test
scope - Generate all classes as test sources.
Generating JAXB classes and matchers as test sources
- Add 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 tosrc/test/resources/
with content:
matcher.gen.annotations=javax.xml.bind.annotation.XmlElement
How to debug Annotation Processors
With remote debugger on maven build
- Run in shell
export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
- Run
mvn clean compile
- Connect with remote debugger to port 8000
With Intellij IDEA
- Open
"Maven Projects"
view - Disclose
"Yandex QATools Annotation Processors"
element - Right-click on Maven phase
"package"
- Click on
"Debug 'annotation-processors'"
It will create a new launcher configuration which can be used to debug project.
NOTE
Not supported: EmptyClass -> EmptyStaticNested -> StaticNestedWithFields