Hamcrest for Kotlin
Kotlin Shell
Latest commit c60f7e7 Oct 17, 2016 @npryce-springer npryce-springer Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/main/kotlin/com/natpryce/hamkrest/matching.kt

README.md

HamKrest - Hamcrest for Kotlin

A reimplementation of Hamcrest to take advantage of Kotlin language features.

Kotlin Build Status Maven Central

Compared to Java:

  • A decent type system means that developers don't have to worry about getting the variance of generic signatures right. Variance is defined on the abstract Matcher type and Kotlin makes sure composition and subtyping work together the way you expect.
  • Syntactic sugar. You can negate a matcher with the ! operator and compose matchers with infix and and or functions:

      assertThat("xyzzy", startsWith("x") and endsWith("y") and !containsSubstring("a"))
    
  • Easier to extend. You can convert named unary predicates into matchers.

      val isBlank = Matcher(String::isBlank)
    
      assertThat(input, isBlank)
    

    As a shortcut, you can pass named functions to the assertThat, and, or and many other functions that take a matcher.

      assertThat(input, String::isBlank)
    

    You can also convert a named binary predicate and the second argument to a matcher for first argument, which works well for extension methods.

      fun String.hasLength(n: Int): Boolean = this.length == n
    
      val isTheRightLength = Matcher(String::hasLength, 8)
    
      assertThat(secretCode, isTheRightLength)
    

    You can use function and property references to match features of a value:

      val isLongEnough = has(String::length, greaterThan(8))
    
      assertThat(password, isLongEnough)
    

    If you like sugar (or don't like punctuation), you can use

      password shouldMatch isLongEnough
      password shouldMatch ::myPasswordFunction
    

    All of these shortcuts produce good, human-readable diagnostics.

Still using Java? The HamKrest API has been crafted to be convenient and idiomatic when used from Java code. And all the generic wildcard bounds work the way you expect.