Simplify Your Tests with OCHamcrest “hasProperty”

October 12, 2011 — 2 Comments

Whenever test code has repeated patterns, there’s an opportunity to make it more expressive and readable. This can sometimes be done by creating a new OCHamcrest matcher.

hasProperty

Property in Europe” by Images_of_Money, used under CC BY 2.0 / Added text

OCHamcrest features a great new matcher submitted by Justin Shacklette: hasProperty.

“hasProperty” is something of a misnomer, because it’s not just for properties. Any method, without arguments, that returns an object, is fair game. But I couldn’t think of a better name; I think it communicates well. Let’s take a look at a before-and-after code example.

“hasProperty”: before

A little before-and-after may show you why I’m so excited about this matcher. Here’s a test I wrote before OCHamcrest 1.6:

- (void)testArrayFromURLStringArray
{
    // given
    NSArray *URLStrings = [NSArray arrayWithObjects:@"one", @"two", nil];

    // when
    NSMutableArray *downloads = [MyDownloader arrayFromURLStringArray:URLStrings];

    // then
    assertThat(downloads, hasCountOf(2));
    MyDownloader *download = [downloads objectAtIndex:0];
    assertThat([image URLString], is(@"one"));
    download = [downloads objectAtIndex:1];
    assertThat([image URLString], is(@"two"));
}

As you can see, the test creates an array of two strings. It passes this array to the method under test, a convenience method that creates an array of MyDownloader objects. The expectation is that the resulting array will have URLString values matching the original array of strings.

What I don’t like about this test is that the verification has to go through a number of steps:

  • Confirm that the resulting array has a count of 2.
  • Get the first element.
  • Confirm its URLString value.
  • Get the second element.
  • Confirm its URLString value.

“hasProperty”: after

Enter the OCHamcrest 1.6 “hasProperty” matcher! Now the same test can be rewritten as follows:

- (void)testArrayFromURLStringArray
{
    // given
    NSArray *URLStrings = [NSArray arrayWithObjects:@"one", @"two", nil];

    // when
    NSMutableArray *downloads = [MyDownloader arrayFromURLStringArray:URLStrings];

    // then
    assertThat(downloads, contains(hasProperty(@"URLString", @"one"),
                                   hasProperty(@"URLString", @"two"),
                                   nil));
}

The “contains” matcher matches an array, in order, with the given matchers. That’s not new. What’s new is the ability to use “hasProperty” to say, “Call a method with this name. Does its return value match the second argument?”

“hasProperty” takes another matcher

In this example, the second arguments of the two “hasProperty” matchers are strings. But as with many other matchers, the argument can also be another matcher. For example,

hasProperty(@"URLString", startsWith(@"https://"))

will match if the URLString value starts with “https://” — a simple way to confirm that you’re using a secure connection.

“hasProperty” with mock objects

I’ve also found that “hasProperty” simplifies tests that use mock objects. Say you want to verify that a method is invoked with an argument having certain properties. I used to have to extract the argument from the mock object, then call the argument to get the property of interest, then verify the value of that property. No more! Now I just set up the mock object’s expectation with a “hasProperty” matcher.

New in OCHamcrest 1.6

So there you have it: The “hasProperty” matcher is new in OCHamcrest 1.6, and will simplify your tests. This latest version also checks that matchers that take nil-terminated lists (like “contains”) actually end with nil — which used to be an easy mistake to make. Download OCHamcrest 1.6 today!

See also: Hamcrest for Objective-C: A Tool for Readable Unit Tests

Question: What other repeated patterns do you encounter in test code? Leave a comment below.

Disclosure of Material Connection: Some of the links in the post above are “affiliate links.” This means if you click on the link and purchase the item, I will receive an affiliate commission. Regardless, I only recommend products or services I use personally and believe will add value to my readers. I am disclosing this in accordance with the Federal Trade Commission’s 16 CFR, Part 255: “Guides Concerning the Use of Endorsements and Testimonials in Advertising.”

If you enjoyed this article, get email updates (it's free).

Email Address:

2 responses to Simplify Your Tests with OCHamcrest “hasProperty”

  1. Nice!

    * How about using a selector, so that if you change the property name the tests should automatically still pass?

    • Jasper,
      It could have been a selector, I suppose. Looking back, I’m not sure why I chose to use a string except maybe that it makes TDD a little easier. But I don’t mind having to update tests to match, as long as the change is centralized.

Leave a Reply

*

Text formatting is available via select HTML.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> 

Have you Subscribed yet? Don't miss a post!