Matchers

来源:互联网 发布:宇通和金龙哪个好 知乎 编辑:程序博客网 时间:2024/05/18 05:34

Matchers is an external addition to the JUnit framework. Matchers were added by the framework called Hamcrest. JUnit 4.8.2 ships with Hamcrest internally, so you don't have to download it, and add it yourself.

Matchers are used with the org.junit.Assert.assertThat() method, which looks like this:

    public void assertThat(Object o, Matcher matcher){        ...    }

You can implement your own Matcher's, but JUnit (Hamcrest) comes with a few builtin matchers you can use. Here are a few examples:

import static org.junit.Assert.*;import static org.hamcrest.CoreMatchers.*;import org.junit.Test;public class MyMatcherTest {    @Test    public void testWithMatchers() {        assertThat("this string", is("this string"));        assertThat(123, is(123));    }}

The assertThat() method takes an object and a Matcher implementation. It is the Matcher that determines if the test passes or fails. The assertThat() method just takes care of the "plumming" - meaning calling the Matcher with the given object.

JUnit (Hamcrest, really) comes with a collection of builtin matchers you can use. In the example above, the org.hamcrest.CoreMatchers.is() method is used to create a Matcher. TheMatcher returned by is() returns true, if the two values compared are equal, and false if not.

The assertThat method throws an exception if the Matcher returns false. If the Matcher returns true, the assertThat() method returns normally. How the Matcher returns true or false, I will get back to later in this text. Right now just imagine that it can.


Chaining Matchers

You can chain some matchers, for instance like this:

@Testpublic void testWithMatchers() {    assertThat(123, not( is(345) ) );}

Notice the chained call not( is(345) ). This is really two matchers combined. The is() method returns one matcher, and the not() method returns another. The matcher returned by not()negates the matcher output of the matcher given as input. In this case, it is the output of the matcher returned by the is() method, that is negated.


Core Matchers

Before you start implementing your own Matcher's, you should look at the core matchers that come with JUnit already. Here is a list of the matcher methods:


Core any()Matches anything is()A matcher that checks if the given objects are equal. describedAs()Adds a descrption to a MatcherLogical allOf()Takes an array of matchers, and all matchers must match the target object. anyOf()Takes an array of matchers, and at least one of the matchers must report that it matches the target object. not()Negates the output of the previous matcher.Object equalTo()A matcher that checks if the given objects are equal. instanceOf()Checks if the given object is of type X or is compatible with type X notNullValue() + 
nullValue()Tests whether the given object is null or not null. sameInstance()Tests if the given object is the exact same instance as another.

Actually, all of the above are static methods which take different parameters, and return a Matcher.

You will have to play around with matchers a little, before you get the hang of them. They can be quite handy.


Custom Matchers

You can write your own matchers and plug into the assertThat() method. Here is an example:

public static Matcher matches(final Object expected){    return new BaseMatcher() {        protected Object theExpected = expected;        public boolean matches(Object o) {            return theExpected.equals(o);        }        public void describeTo(Description description) {            description.appendText(theExpected.toString());        }    };}

The static method matches() creates a new matcher and returns it.

This matcher is an anonymous subclass of the class BaseMatcher. The JUnit documentation states that you should always extend BasreMatcher rather than implement the Matcher interface yourself. Thus, if new methods are added to Matcher in the future, BaseMatcher can implement them. Your subclasses will then automatically get those methods too. That will avoid breaking your code.

Here is how to use this custom matcher:

@Testpublic void testThat() {    MyUnit myUnit = new MyUnit();    assertThat(myUnit.getTheSameObject(), matches("constant string"));}

Simple, isn't it? You just embed the call to the static method matches() inside the assertThat()method.


原创粉丝点击