« It's Alive! | Main | A Pattern By Any Other Name Would Still Sell As Well »

March 14, 2004

RE assertions in JUnit

Whilst busily TDDing the other day, I found myself writing a lot of test code like:

assertTrue(foo.endsWith("bar"));

where foo and bar are both of type String.

My tests didn't care how the start of foo looked, only the end so I didn't want to make them too brittle by using assertEquals.

And here's the rub...

I really like assertEquals. The thing which raises this method above the rest of JUnit's is that a failure of one of these calls results in an instantly useful error message along the lines of "Expected 'foo' but got 'bar'". All you get when an assertTrue fails is a most unhelpful AssertionFailedError.

So, to allow me to maintain my fidelity to assertEquals whilst still keeping my tests fairly clear and loose, I came up with:

    public void assertLike(String expected, String actual) throws AssertionFailedError {
        Pattern pattern = Pattern.compile(expected, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(actual);
        try {
            assertTrue(matcher.find());
        } catch (AssertionFailedError e) {
            throw new ComparisonFailure("RE comparison failed - ", expected, actual);
        }
    }

In short, I'm using the inbuilt JDK RE classes to provide "fuzzy" matching in assertion checks and, if a check fails, emulating an assertEquals failure to present the error in the format I like. The method can be invoked as follows:

assertLike(".bar", foo);

Using RE matching in assertion easily leads to a far richer set of string assertion methods (wrapping assertLike) along the lines of:

  • assertEndsWith
  • assertBeginsWith
  • assertContains
  • assertDoesNotContain

However, I'll leave this stuff as an exercise for the reader.

p.s. Eclipse does a really nice job of present these errors in it's JUnit plugin. I'll post a screenshot as soon as I work out how to post images to this blog.

Posted by Andy Marks at March 14, 2004 07:24 PM

Comments

Actually, you can use the overloaded AssertTrue method in which the first parameter is a String that displays when the assertion fails. Such as
Asserts.assertTrue("The value of foo did not end in bar", foo.endsWith("bar"));

In fact, all of the assert methods in JUnit have this overloaded method. Most of the other assert methods are convenience methods that end up using assertTrue anyway.

Posted by: Pamela at March 24, 2004 11:02 AM

The problem, of course, is that the convenience methods are exactly that: convenient. If you've got a common test, writing a new convenience method helps a lot.

One I often end up doing is an assertContentsEquals(), where I verify that two collections hold the same data.

Andy, if I was you, I'd put an explanatory message into the assertTrue call...

Posted by: Robert Watkins at March 31, 2004 08:57 PM

Post a comment

Thanks for signing in, . Now you can comment. (sign out)

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)


Remember me?