[Alexandre Martins] Hamcrest Out Of Test Code!

It’s been a while since I read some interesting posts showing creative uses of Hamcrest library out of test code. Since then I’ve been proscrastinating to implement my own version, trying strongly typed java delegates.

Thankfully this week I came across a nice API called hamcrest-collections. It uses Hamcrest to implement features such as select, reject, map, reduce and zip familiar from languages like Ruby and Python.

Selectors

Selectors can be used to select or reject items that matches a given Matcher, from any iterable object. It reminds me the Specification Pattern from Domain-Driven Design, which is also used for querying objects that satisfies defined specifications.

public static final Person john = new Person("John", 28);
public static final Person nicole = new Person("Nicole", 12);
public static final Person ryan = new Person("Ryan", 23);
public static final Person nathan = new Person("Nathan", 18);

public static final List list() {
    return Arrays.asList(john, nicole, ryan, nathan);
}



The code below selects from the list of users defined above, the ones that are under twenty.

@Test
public void should_select_only_people_under_twenty_years_old() {
    List users = Person.list();
    Iterable underTwentyList = select(users, underAge(20));
    assertThat(underTwentyList, hasItems(nicole, nathan));
    assertThat(underTwentyList, not(hasItems(john, ryan)));
}



The code below rejects all the users that are under twenty.

@Test
public void should_reject_every_people_under_twenty_years_old() {
    List users = Person.list();
    Iterable aboveTwentyList = reject(users, underAge(20));
    assertThat(aboveTwentyList, hasItems(john, ryan));
    assertThat(aboveTwentyList, not(hasItems(nicole, nathan)));
}


Map and Reduce

Map is used to apply a function onto each item in any iterable object, whereas Reduce combines all these elements, applying a Reducer implementation. In our example, we map the timesTwo function, that doubles each element in the list, and then we reduce it by adding up all of them.

@Test
public void should_double_each_number_in_the_list_then_sum_all_of_them() {
    List numbers = Arrays.asList(1, 2, 3);
    MultiplyBy timesTwo = new MultiplyBy(2);

    Iterable result = map(numbers, timesTwo);
    assertThat(result, hasItems(2, 4, 6));

    Integer sum = reduce(result, new Sum());
    assertThat(sum, equalTo(12));
}


public class MultiplyBy implements Function {
    private Integer factor;

    public MultiplyBy(Integer factor) {
        this.factor = factor;
    }

    public Integer apply(Integer number) {
        return (int)number * factor;
    }
}


public class Sum implements Reducer {
    public Integer apply(Integer first, Integer second) {
        return first + second;
    }
}


Despite the bias created by some developers, that Hamcrest should not be used anywhere else but test code, specially after JUnit has defined it as its new matcher library, just ignore it and add these features to your runtime library, so that you can let your creativity drive you when developing. Get rid of “for” loops from your life! :)