Revision: 157
Author:
plazt...@gmail.com
Date: Tue Jun 11 14:41:51 2013
Log: Edited wiki page Argument_Matching through web user interface.
http://code.google.com/p/mockitopp/source/detail?r=157
Modified:
/wiki/Argument_Matching.wiki
=======================================
--- /wiki/Argument_Matching.wiki Fri Jun 7 15:03:21 2013
+++ /wiki/Argument_Matching.wiki Tue Jun 11 14:41:51 2013
@@ -1,6 +1,8 @@
#labels Featured
== Argument Matching ==
-Usually, test cases are required to cover a large permutation of user
inputs. This can be troublesome in cases where the system under test has
several underlying dependencies. Usually, when using a mock framework to
provide the dependencies for the system under test, each dependency will
have to stubbed with 1:1 mappings of the user inputs. Overtime this makes
test cases quite brittle and becomes a maintenance liability. To help
reduce this overhead generic argument matchers are available
({{{<mockitopp/matchers>}}}) to use when stubbing method invocations. These
matchers work with all primitive types, but do note that complex types
(classes, etc) *must* implement operator==() correctly in order to be used.
If your complex types do not implement operator==, you will get a somewhat
messy compile error with lots of template expansion to sift through.
+Usually, test cases are required to cover a large permutation of user
inputs. This can be troublesome in cases where the system under test has
several underlying non-trivial dependencies. Non-trivial dependencies are
those that are slow (network or disk I/O), flaky (connections to
third-party services), or dependencies whose quality is volatile. All of
these things are barriers to fast, dependable tests that whose legitimate
failure are easy to diagnose.
+
+Usually, when using a static mock framework to provide the dependencies
for the system under test, each dependency will have to stubbed with 1:1
mappings of the user inputs. Overtime this makes test cases quite brittle
and becomes a maintenance liability. To help reduce this overhead generic
argument matchers are available ({{{<mockitopp/matchers>}}}) to use when
stubbing method invocations. These matchers work with all primitive types,
but do note that complex types (classes, etc) *must* implement operator==()
correctly in order to be used. If your complex types do not implement
operator==, you will get a somewhat messy compile error with lots of
template expansion to sift through.
The best examples of how to use mockitopp are it's own test source code
located in the test/ subdirectory. If you have problems using the examples
below, study the test source code.
@@ -13,6 +15,8 @@
using mockitopp::matcher::equal;
using mockitopp::matcher::is_not;
+// this is a micro-test framework, real projects should use
+// cgreen, Catch, Boost::Unit, gtest, or some other framework
#include <cassert>
#define ASSERT_TRUE(expr) assert( (expr) == true )
#define ASSERT_FALSE(expr) assert( (expr) == false )
@@ -38,14 +42,17 @@
{
mockitopp::mock_object<interface> mock;
+ // first expectation
mock(&interface::func1)
.when(null<int*>())
.thenReturn(true);
+ // second expectation
mock(&interface::func1)
.when(any<int*>())
.thenReturn(false);
+ // third expectation
mock(&interface::func2)
.when(is_not(equal<const std::string&>("foo")))
.thenReturn(true);
@@ -62,6 +69,15 @@
return 0;
}
}}}
+
+The first expectation set is that our mocked instance of the `interface`
type will have `func1(int*)` called with a `NULL`. If it gets called with
something other than `NULL`, the mocked instance will throw an exception.
This is fantastic for debugging when there are regressions in the way your
code interacts with it's collaborators. When the expectation fails, the
stack trace in the debugger tells you *exactly* where the incorrect input
came from as it happened -- not with log messages are the fact. This makes
not only for easy-to-read tests as documentation, but fast debugging cycles
when your tests do fail.
+
+The `null<T>` matcher is an interesting one, in that one typically will
combine is with the `is_not()` modifier. This can be useful when the exact
pointer value being passed in is not reasonably known to the test due to
proper encapsulation -- it just needs to not be `NULL`.
+
+The second expectation set on our mocked instance of the `interface` type
uses the `any<T>` matcher. This is a way to say "we don't care what the
value is". This can be useful for focusing the reader of the test on what
is relevant to the given test. By over-specifying exact values for all
parameters to mocked methods, we are may be over-communicating and making
it harder to determine what's relevant to the exact scenario and action
(GivenWhenThen) versus others in the suite. Also, over-specification in
mocks can make them more brittle. When a regression occurs, more tests may
fail at once, creating noise for the developer to sift through. In
addition, over-specification can mean changes in the implementation that
require more tests and mock expectations need to be updated. So, keeping
tests and mock expectations focused on the "simplest thing that could
possible work" to pin down relevant behavior and protect against
regressions is highly recommended -- the `any<>` matcher is one of the
great tools to accomplish that. Keep in mind that even with the any<>
matcher, types need to implement `operater==()`; if they don't, you'll get
a compile error.
+
+The third expectation uses the `equal<>` matcher, combined with the
`is_not()` modifier. Note that the template parameter, `const
std::string&`, matches the `interface::func2` signature *exactly*. If there
is even a slight mismatch -- a missing const, value instead of reference,
etc -- then a compile error will occur. Also, if the type supplied in the
`thenReturn()` clause does not match the mocked method signature, you will
get a similar compile error.
+
=== [
http://www.boost.org/doc/libs/1_36_0/libs/regex/doc/html/index.html
TR1 <regex>] ===
{{{
@@ -93,6 +109,7 @@
int main()
{
mockitopp::mock_object<interface> mock;
+ // the following line incorrectly fails on GCC <= 4.8.1
mock(&interface::func).when(regex("[0-9]*")).thenReturn(true);
mock(&interface::func).when(regex("he.*ld")).thenReturn(true);
interface& obj = mock.getInstance();