Link

Matchers (JUnit 5, Hamcrest and AssertJ)

Table of contents

  1. Hamcrest
  2. AssertJ
  3. JUnit 5, Hamcrest and AssertJ

Hamcrest

Hamcrest is a framework for writing matcher objects allowing ‘match’ rules to be defined declaratively.

  1. Add the Hamcrest dependency

     dependencies {
       testImplementation 'org.hamcrest:hamcrest:2.2'
     }
    
  2. Example

     package demo;
    
     import org.junit.jupiter.api.Test;
    
     import java.math.BigDecimal;
    
     import static org.hamcrest.MatcherAssert.assertThat;
     import static org.hamcrest.core.CombinableMatcher.either;
     import static org.hamcrest.core.Is.is;
     import static org.hamcrest.core.Is.isA;
     import static org.hamcrest.core.IsEqual.equalTo;
     import static org.hamcrest.core.StringStartsWith.startsWith;
     import static org.hamcrest.number.IsCloseTo.closeTo;
     import static org.hamcrest.number.OrderingComparison.comparesEqualTo;
     import static org.hamcrest.number.OrderingComparison.greaterThan;
     import static org.hamcrest.number.OrderingComparison.lessThan;
    
     class AppTest {
    
       @Test
       public void tryingOutHamcrest() {
         assertThat( "my string", equalTo( "my string" ) );
         assertThat( "Hello everyone", startsWith( "Hello" ) );
    
         assertThat( 10, is( greaterThan( 5 ) ) );
         assertThat( 10, isA( Integer.class ) );
         assertThat( 10, either( greaterThan( 50 ) ).or( lessThan( 20 ) ) );
    
         assertThat( new BigDecimal( "10" ), comparesEqualTo( new BigDecimal( "10.00" ) ) );
         assertThat( 10.01, closeTo( 10, 0.02 ) );
       }
     }
    

AssertJ

Assertj is a java library providing a rich set of assertions, truly helpful error messages, improves test code readability and is designed to be super easy to use.

  1. Add the Assertj dependency

     dependencies {
       testImplementation 'org.assertj:assertj-core:3.16.1'
     }
    
  2. Example

     package demo;
    
     import org.junit.jupiter.api.Test;
    
     import java.math.BigDecimal;
    
     import static org.assertj.core.api.Assertions.assertThat;
     import static org.assertj.core.api.Assertions.offset;
    
     class AppTest {
    
       @Test
       public void tryingOutAssertJ() {
         assertThat( "my string" ).isEqualTo( "my string" );
         assertThat( "Hello everyone" ).startsWith( "Hello" );
    
         assertThat( 10 ).isGreaterThan( 5 );
         assertThat( 10 ).isInstanceOfAny( Integer.class );
         /* Using Lambdas here */
         assertThat( 10 ).satisfiesAnyOf(
             i -> assertThat( i ).isGreaterThan( 50 ),
             i -> assertThat( i ).isLessThan( 20 )
         );
    
         assertThat( new BigDecimal( "10" ) ).isEqualByComparingTo( new BigDecimal( "10.00" ) );
         assertThat( 10.01 ).isCloseTo( 10, offset( 0.02 ) );
       }
     }
    

JUnit 5, Hamcrest and AssertJ

LibraryTest RunnerMatcher
JUnit 5YESYES
HamcrestNOYES
AssertJNOYES

According to Google Trends, the matchers share similar popularity.

Harmcrest vs AssertJ

The good news is that these are not mutually exclusive and it is not uncommon to find them both.

dependencies {
  testImplementation 'org.junit.jupiter:junit-jupiter:5.7.0-M1'
  testImplementation 'org.hamcrest:hamcrest:2.2'
  testImplementation 'org.assertj:assertj-core:3.16.1'
}

With that said, using both Hamcrest and AssertJ may be challenging as both use the same method name assertThat() and thus cannot just static import this method.

package demo;

import org.assertj.core.api.Assertions;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;

class AppTest {

  @Test
  public void tryingOutBothInSameTest() {
    Assertions.assertThat( 10 ).isEqualTo( 10 );
    MatcherAssert.assertThat( 10, Matchers.equalTo( 10 ) );
  }
}