TotT: Literate Testing With Matchers
By Zhanyong G. Mock Wan in Google KirklandAlright, it sounds like a good idea to verify that matchmakers can read and write. How does this concern us programmers, though?
Actually, we are talking about a way of writing tests here – a way that makes both the test code and its output read like English (hence “literate”). The key to this technique is matchers, which are predicates that know how to describe themselves. For example, in Google C++ Mocking Framework, ContainsRegex("Ahcho+!") is a matcher that matches any string that has the regular expression "Ahcho+!" in it. Therefore, it matches "Ahchoo!" and "Ahchoooo! Sorry.", but not "Aha!".
What's this to do with test readability, anyway? It turns out that matchers, whose names are usually verb phrases, lend themselves easily to an assertion style that resembles natural languages. Namely, the assertion
EXPECT_THAT(value, matcher);
succeeds if value matches matcher. For example,
#include <gmock/gmock.h>
using ::testing::Contains;
...
EXPECT_THAT(GetUserList(), Contains(admin_id));
using ::testing::Contains;
...
EXPECT_THAT(GetUserList(), Contains(admin_id));
verifies that the result of GetUserList() contains the administrator.
Now, pretend the punctuations aren't there in the last C++ statement and read it. See what I mean?
Better yet, when an EXPECT_THAT assertion fails, it will print an informative message that includes the expression being validated, its value, and the property we expect it to have – thanks to a matcher's ability to describe itself in human-friendly language. Therefore, not only is the test code readable, the test output it generates is readable too. For instance, the above example might produce:
Value of: GetUserList()
Expected: contains "yoko"
Actual: { "john", "paul", "george", "ringo" }
Expected: contains "yoko"
Actual: { "john", "paul", "george", "ringo" }
This message contains relevant information for diagnosing the problem, often without having to use a debugger.
To get the same effect without using a matcher, you'd have to write something like:
std::vector<std::string> users = GetUserList();
EXPECT_TRUE(VectorContains(users, admin_id))
<< " GetUserList() returns " << users
<< " and admin_id is " << admin_id;
EXPECT_TRUE(VectorContains(users, admin_id))
<< " GetUserList() returns " << users
<< " and admin_id is " << admin_id;
which is harder to write and less clear than the one-liner we saw earlier.
Google C++ Mocking Framework (http://code.google.com/p/googlemock/) provides dozens of matchers for validating many kinds of values: numbers, strings, STL containers, structs, etc. They all produce friendly and informative messages. See http://code.google.com/p/googlemock/wiki/CheatSheet to learn more. If you cannot
find one that matches (pun intended) your need, you can either combine existing matchers, or define your own from scratch. Both are quite easy to do. We'll show you how in another episode. Stay tuned!
No comments:
Post a Comment