Here`s how to implement a Custom Matcher in Hamcrest.
Hamcrest provides various Matchers such as containsString()
, closeTo()
, etc. However, there are test cases that are difficult to implement with the matchers provided by default.
Hamcrest provides the following abstract classes, which can be implemented to create custom matchers.
- TypeSafeMatcher
- TypeSafeDiagnosingMatcher
Set project dependencies
If your project uses Gradle, add java-hamcrest
as below in java-hamcrest
.
dependencies {
testImplementation 'org.hamcrest:java-hamcrest:2.0.0.0'
}
Custom Matcher (TypeSafeMatcher)
You can create a Custom Matcher by implementing TypeSafeMatcher.
If you inherit TypeSafeMatcher, you need to override the following two methods.
public class IsInteger extends TypeSafeMatcher<String> {
@Override
protected boolean matchesSafely(String item) {
// return true if it matches
}
@Override
public void describeTo(Description description) {
// description for failure message
}
}
- matchesSafely : Returns a boolean indicating whether the item passed as an argument matches any condition. If true is returned, the test passes
- describeTo : Contents displayed when the test fails
Matcher to test if a string is an Integer
The IsInteger class below is a Matcher that checks if a string is an Integer.
In matchesSafely()
, simply Integer.parseInt()
checks whether it is an Integer or not.
In describeTo()
, we entered a message that the string must consist of Integers.
public class IsInteger extends TypeSafeMatcher<String> {
@Override
protected boolean matchesSafely(String str) {
try {
Integer.parseInt(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public void describeTo(Description description) {
description.appendText("A String of Integer");
}
public static Matcher<String> isInteger() {
return new IsInteger();
}
}
The Matcher implemented above can be used with assertThat like this: When passing Matcher as the second argument, create a Matcher object with new IsInteger()
and pass it.
@Test
public void testCustomMatcher_isInteger1() {
String num = "1234";
assertThat(num, new IsInteger());
}
Because the readability of creating and passing an object is not good, the IsInteger class is added as a static method that creates and returns a Custom Matcher object as follows.
public static Matcher<String> isInteger() {
return new IsInteger();
}
Now, with this method, you can simply pass a Custom Matcher to assertThat()
as shown below.
@Test
public void testCustomMatcher_isInteger2() {
String num = "1234";
assertThat(num, isInteger());
}
Failure message
In the test below, 1234.56
will fail because it is not an Integer.
@Test
public void testCustomMatcher_isInteger3() {
String notNum = "1234.56";
assertThat(notNum, isInteger());
}
If the test fails, the following failure message is output. The message output after Expected:
will be the string entered in describeTo()
.
Expected: A String of Integer
but: was "1234.56"
Use with other Matchers
Custom Matcher can be used with default matchers such as is()
and not()
.
@Test
public void testCustomMatcher_isInteger4() {
String notNum = "1234.56";
assertThat(notNum, not(isInteger()));
}
Custom Matcher (TypeSafeDiagnosingMatcher)
This time we will create a Custom Matcher by implementing the TypeSafeDiagnosingMatcher class. TypeSafeDiagnosingMatcher can set more detailed failure messages than TypeSafeMatcher.
Matcher to test if Integer is even
This time we implement a Matcher called IsEven that checks if an Integer is even.
public class IsEven extends TypeSafeDiagnosingMatcher<Integer> {
@Override
protected boolean matchesSafely(Integer integer, Description description) {
description.appendText("was ").appendValue(integer)
.appendText(", which is an Odd number");
return integer % 2 == 0;
}
@Override
public void describeTo(Description description) {
description.appendText("An Even Number");
}
public static Matcher<Integer> isEven() {
return new IsEven();
}
}
In the case of TypeSafeDiagnosingMatcher, you can implement the following two methods.
TypeSafeMatcher does not pass a Description as an argument to matchesSafely()
, but does pass it here.
- matchesSafely(Integer integer, Description description)
- describeTo(Description description)
If you look at the implementation of matchesSafely()
, put a message in the description. This message is only output when the test fails.
@Override
protected boolean matchesSafely(Integer integer, Description description) {
description.appendText("was ").appendValue(integer)
.appendText(", which is an Odd number");
return integer % 2 == 0;
}
describeTo()
can be implemented like TypeSafeMatcher.
failure message
The test below will fail because 13 is an odd number.
@Test
public void testCustomMatcher_isEven2() {
Integer num2 = 13;
assertThat(num2, isEven());
}
When I test it, the failure message is output like this:
You can see that the message set in matchesSafely()
is output like was <13>, which is an Odd number
.
Expected: An Even Number
but: was <13>, which is an Odd number
Related Posts
- Java - Remove items from List while iterating
- Java - How to find key by value in HashMap
- Java - Update the value of a key in HashMap
- Java - How to put quotes in a string
- Java - How to put a comma (,) after every 3 digits
- BiConsumer example in Java 8
- Java 8 - Consumer example
- Java 8 - BinaryOperator example
- Java 8 - BiPredicate Example
- Java 8 - Predicate example
- Java 8 - Convert Stream to List
- Java 8 - BiFunction example
- Java 8 - Function example
- Java - Convert List to Map
- Exception testing in JUnit
- Hamcrest Collections Matcher
- Hamcrest equalTo () Matcher
- AAA pattern of unit test (Arrange/Act/Assert)
- Hamcrest Text Matcher
- Hamcrest Custom Matcher
- Why Junit uses Hamcrest
- Java - ForkJoinPool
- Java - How to use Futures
- Java - Simple HashTable implementation
- Java - Create a file in a specific path
- Java - Mockito의 @Mock, @Spy, @Captor, @InjectMocks
- Java - How to write test code using Mockito
- Java - Synchronized block
- Java - How to decompile a ".class" file into a Java file (jd-cli decompiler)
- Java - How to generate a random number
- Java - Calculate powers, Math.pow()
- Java - Calculate the square root, Math.sqrt()
- Java - How to compare String (==, equals, compare)
- Java - Calculate String Length
- Java - case conversion & comparison insensitive (toUpperCase, toLowerCase, equalsIgnoreCase)