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 numberRelated 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 Custom Matcher
- Hamcrest Text 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)