Hamcrest extended matcher for Annotations
The library is used to help unit testing of annotations. The range of annotations that can be tested are :-
- Types - Classes, Interfaces, Enums
- Constructors
- Fields
- Methods
- Constructor Parameter
- Method Parameter
To use the official release of Annotation matchers, please add the following snippet to your pom.xml
<dependency>
<groupId>com.zaradai</groupId>
<artifactId>matchers</artifactId>
<version>0.2</version>
</dependency>The following examples describe how to use the matcher library. Each example will show the code under test and a passing test. For every type there are 4 specific tests that can be run.
- AnnotatedWith: Check for annotation existence.
- AnnotatedWithParam: Check for annotation and that it has the specified parameter.
- AnnotatedWithParamValue: Check for annotation and that it has the specified parameter and value. The value is matched using a Matcher.
- AnnotatedWithParamValue: Check for annotation and that it has the specified parameter and value. The value is matched using an equality test.
For classes, interfaces, enums, asserts that the type has the specified annotation.
Code to be tested
@Table(name="categories")
public class Category {
}Ensure the Category class is annotated with Table annotation.
assertThat(category, is(classAnnotatedWith(Entity.class)));Ensure the Category class is annotated with Table annotation and that the annotation has a parameter called name.
assertThat(category, is(classAnnotatedWithParam(Table.class, "name")));Ensure the Category class is annotated with Table annotation and that the annotation has a parameter called name with value categories using a matcher.
assertThat(category, is(classAnnotatedWithParamValue(Table.class, "name", is("categories"))));Ensure the Category class is annotated with Table annotation and that the annotation has a parameter called name with value categories using a value to match against.
assertThat(category, is(classAnnotatedWithParamValue(Table.class, "name", "categories")));For constructors I shall use the ConstructorProperties annotation that shows how the parameters of that constructor correspond to the constructed object's getter methods. This example will also show how much neater using a value matcher is.
Code to be tested
public class Point {
private final int x;
private final int y;
@ConstructorProperties({"x", "y"})
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}Ensure the Point class is annotated with ConstructorProperties annotation. The specific constructor we are interested in has a signature of 2 int types so these have to be include so that the matcher can locate the constructor under test.
assertThat(point, is(constructorAnnotatedWith(ConstructorProperties.class, int.class, int.class)));Now ensure the annotation has a value parameter.
assertThat(point, is(constructorAnnotatedWithParam(ConstructorProperties.class, "value", int.class, int.class)));Check to ensure we have supplied the correct values to the annotation. We shall use a matcher to ensure that all values have been supplied in the correct order.
assertThat(point, is(constructorAnnotatedWithParamValue(ConstructorProperties.class, "value", arrayContaining("x", "y"), int.class, int.class)));Finally similar to above but a bit more long winded, matching using equality.
String[] toTest = {"x", "y"};
assertThat(point, is(constructorAnnotatedWithParamValue(ConstructorProperties.class, "value", toTest, int.class, int.class)));To test field annotations, one is required to specify the field name. For the test code I shall be looking for javax persistence Column annotation.
Code to be tested
@Column(name = "DESC")
private String description;Ensure field is appropriately annotated.
assertThat(category, is(fieldAnnotatedWith(Column.class, "description")));Check for the name parameter.
assertThat(category, is(fieldAnnotatedWithParam(Column.class, "name", "description")));Check the name parameter has value DESC using a matcher.
assertThat(category, is(fieldAnnotatedWithParamValue(Column.class, "name", is("DESC"), "description")));Check the name parameter has value DESC using equality check.
assertThat(category, is(fieldAnnotatedWithParamValue(Column.class, "name", "DESC", "description")));To identify the method being tested within your class you must specify the simple method name and its argument types in order.
The code to test will be similar to field above but on a no-arg method.
Code to be tested
@Column(name = "DESC")
public String getDescription() {
return description;
}Ensure required method is annotated.
assertThat(category, is(methodAnnotatedWith(Column.class, "getDescription")));Check for the name parameter.
assertThat(category, is(methodAnnotatedWithParam(Column.class, "name", "getDescription")));Check the name parameter has value DESC using a matcher.
assertThat(category, is(methodAnnotatedWithParamValue(Column.class, "name", is("DESC"), "getDescription")));Check the name parameter has value DESC using equality check.
assertThat(category, is(methodAnnotatedWithParamValue(Column.class, "name", "DESC", "getDescription")));In addition to specifying the constructor signature using its types (in order), one also needs to indicate the parameter to test using its position. Positional indexing is 0 based.
The code to be tested will be annotated with javax persistence Named annotation and the constructor signature with be String, int.
Code to be tested
@Inject
public NamedInjection(String notNamed, @Named("test") int named) {
}Ensure required constructor parameter is annotated.
assertThat(namedInjection, is(constructorParameterAnnotatedWith(Named.class, 1, String.class, int.class)));Check for the value parameter.
assertThat(namedInjection, is(constructorParameterAnnotatedWithParam(Named.class, "value", 1, String.class, int.class)));Check the value parameter has value test using a matcher.
assertThat(namedInjection, is(constructorParameterAnnotatedWithParamValue(Named.class, "value", is("test"), 1, String.class, int.class)));Check the value parameter has value test using equality check.
assertThat(namedInjection, is(constructorParameterAnnotatedWithParamValue(Named.class, "value", "test", 1, String.class, int.class)));In addition to specifying the method's signature using its types (in order) and method name, one also needs to indicate the parameter to test using its position. Positional indexing is 0 based.
To make things simple I shall reuse the Named annotation from above to decorate the method parameter.
Code to be tested
@Inject
public void namedInjection(String notNamed, @Named("test") int named) {
}Ensure required method parameter is annotated..
assertThat(namedInjection, is(methodParameterAnnotatedWith(Named.class, 1, "namedInjection", String.class, int.class)));Check for the value parameter.
assertThat(namedInjection, is(methodParameterAnnotatedWithParam(Named.class, "value", 1, "namedInjection", String.class, int.class)));Check the value parameter has value test using a matcher.
assertThat(namedInjection, is(methodParameterAnnotatedWithParamValue(Named.class, "value", is("test"), 1, "namedInjection", String.class, int.class)));Check the value parameter has value test using equality check.
assertThat(namedInjection, is(methodParameterAnnotatedWithParamValue(Named.class, "value", "test", 1, "namedInjection", String.class, int.class)));