Commits

grahamcarlyle committed b84feef

start with old code

Comments (0)

Files changed (10)

+todo:
++ support for properties
++ add constraints and(), not(), or()
++ build scripts in CVS (Scons?)
+
+possibly:
++ constraint base class to allow non-derived constraints to default to an equality match against the parameter. Would allow more compact argument constraints for the common case of equality e.g. mock.foo('bar').will(...)
++ constrain allowable order of builder methods
++ pull out dispatcher functionality to allow different matching strategies (LIFO, FIFO)?
+
+<html>
+
+<head>
+<title>pMock: a mock object library for Python</title>
+</head>
+
+<body>
+
+<h1>pMock</h1>
+
+<p>pMock is a Python module for testing Python code using <a href="http://www.mockobjects.com">mock objects</a>.</p>
+
+<pre>
+...
+import pmock
+...
+class InstrumentTest(unittest.TestCase):
+    def test_low_quality_analysis(self):
+        analyser_mock = pmock.Mock()
+        analyser_mock.expects().analyse(pmock.eq("123")).will(pmock.return_value("30"))
+        instrument = Instrument(analyser_mock)
+        instrument.insert("sample#123")
+        self.assert_(instrument.is_low_quality_indicator_on())
+        analyser_mock.verify()
+...
+</pre>
+
+<p>Inspired by the Java <a href="http://www.jmock.org">jMock</a> library, pMock makes the writing of unit tests using mock object techniques easier.</p>
+
+The typical sequence of steps in a test involving pMock mock objects are:
+
+<ul>
+<li>Mock objects are created with expectations and simple behaviours</li>
+<li>Code under test is called with the mock objects</li>
+<li>Code state is asserted as in normal unit tests</li>
+<li>The mock objects' expectations are verified (basically another assertion)</li>
+</ul>
+
+See the <a href="overview.html">overview</a> for an introduction on how to use pMock in your unit tests.
+
+<h2>Requirements</h2>
+<ul>
+<li>pMock is currently written for versions of Python >= 2.3</li>
+<li>pMock is licensed under the same terms as Python</li>
+</ul>
+
+<h2>Download</h2>
+<p><a href="http://prdownloads.sourceforge.net/pmock/pmock-0.3.tar.gz?download">pmock 0.3</a></p>
+
+<h2>Documentation</h2>
+<ul>
+<li><a href="overview.html">Overview</a> of API</li>
+<li><a href="api/index.html">API</a> rendered by epydoc</li>
+</ul>
+
+<h2>Development</h2>
+<p>Sourceforge <a href="http://sourceforge.net/projects/pmock">project page</a></p>
+<p>Browse the <a href="http://cvs.sourceforge.net/viewcvs.py/pmock/pmock/src/">source</a> in CVS</p>
+<p>Author: Graham Carlyle (grahamcarlyle at users dot sourceforge dot net)
+<p>
+<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=104082&amp;type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" /></a>
+</p>
+
+</body>
+</html>
+<html>
+
+<head>
+<title>pMock: Overview of API</title>
+</head>
+
+<body>
+
+<h1>Overview of the pMock API</h1>
+
+<ul>
+<li><a href="#CreatingMocks">Creating mocks<a/></li>
+<li><a href="#ArgumentExpectations">Argument expectations<a/></li>
+<li><a href="#NumberOfCallsToTheSameMethod">Number of calls to the same method</a></li>
+<li><a href="#CallOrderExpectations">Call order expectations<a/></li>
+<li><a href="#MockBehaviour">Mock behaviour<a/></li>
+<li><a href="#Stubs">Stubs<a/></li>
+<li><a href="#DefaultBehaviourForUndefinedMethods">Default behaviour for undefined methods<a/></li>
+<li><a href="#FromImports"><code>from</code> imports<a/></li>
+<li><a href="#TestBaseClass">Test base class<a/></li>
+<li><a href="#FurtherInformation">Further information<a/></li>
+</ul>
+
+<h2 id="CreatingMocks">Creating mocks</h2>
+
+A mock object is created to represent a real object for the purposes of a unit test. Using a mock object rather than the real object can be useful if the real object is difficult to construct, hasn't been written yet or causes awkward side effects in use.
+
+<pre>
+    import pmock
+    ...
+    mock = pmock.Mock()
+</pre>
+
+Expectations are defined for the methods that are meant to be called on the mock object.
+
+<pre>
+    mock.expects(pmock.once()).render()
+</pre>
+
+The mock can now be called with the expected method.
+
+<pre>
+    mock.render()
+</pre>
+
+Calling the mock with unexpected methods causes an exception to be raised.
+
+<p>When the mock objects have been set up, they are then used in the unit test as the real objects would have been.
+
+<pre>
+    pictures = [mock]
+    gallery = Gallery(pictures)
+    gallery.render()
+</pre>
+
+After the test's normal assertions have been made, an assertion that the mock's expectations have been satisfied should be made.
+
+<pre>
+    mock.verify()
+</pre>
+
+If any of the mock's expectations haven't been satisfied, such as an expected method not having been called, then the <code>verify</code> call raises an exception.
+
+<h2 id="ArgumentExpectations">Argument expectations</h2>
+
+Expectations can be set on the arguments passed to the mock's methods.
+
+<pre>
+    mock.expects(pmock.once()).render(pmock.eq(640), pmock.eq(480))
+</pre>
+
+The arguments to the expectation's mocked method are constraint objects which are evaluated on the actual arguments when a call is made to the mock object. If an argument doesn't satisfy its constraint then the expectation remains unsatisfied.
+
+<pre>
+    mock.expects(pmock.once()).render(brush=pmock.same(print.BIG_BRUSH))
+</pre>
+
+More flexible argument constraints can be defined using a slightly more verbose set of methods.
+
+<pre>
+    mock.expects(pmock.once()).method("render") # any arguments allowed
+    mock.expects(pmock.once()).method("render").with_at_least(brush=pmock.same(print.BIG_BRUSH))
+</pre>
+
+
+<h2 id="NumberOfCallsToTheSameMethod">Number of calls to the same method</h2>
+
+The argument to the <code>expects</code> method describes how often the expected method can be called.
+
+<pre>
+    mock.expects(pmock.once()).boil()
+    mock.expects(pmock.at_least_once()).simmer()
+    mock.expects(pmock.never()).fry()
+</pre>
+
+<h2 id="CallOrderExpectations">Call order expectations</h2>
+
+The order of calls to the mock object can be described with the <code>after</code> method.
+
+<pre>
+    mock.expects(pmock.once()).invalidate()
+    mock.expects(pmock.once()).render().after("invalidate")
+</pre>
+
+<p>An explicit id can be set for an expectation and used in the <code>after</code> method instead of using the method name.
+
+<pre>
+    mock.expects(pmock.once()).add(pmock.eq(10)).id("add #1")
+    mock.expects(pmock.once()).add(pmock.eq(15)).id("add #2").after("add #1")
+    mock.expects(pmock.once()).add(pmock.eq(5)).after("add #2")
+</pre>
+
+The order of calls can also be defined across different mock objects.
+
+<pre>
+    other_mock = pmock.Mock()
+    other_mock.expects(pmock.once()).add()
+    mock = pmock.Mock()
+    mock.expects(pmock.once()).sum().after("add", other_mock)
+</pre>
+
+
+<h2 id="MockBehaviour">Mock behaviour</h2>
+
+The mocked methods can be provided with simple behaviours using the <code>will</code> method.
+
+<pre>
+    mock.expects(pmock.once()).calculate().will(pmock.return_value(20))
+    mock.expects(pmock.once()).consume().will(pmock.raise_exception(RuntimeError("invalid")))
+</pre>
+
+<h2 id="Stubs">Stubs</h2>
+
+Stubs allow behaviours to be specified for methods that can be called any number of times and are not to be included in the mock's verification check.
+
+<pre>
+    mock.stubs().sleep().will(pmock.return_value(True))
+</pre>
+
+<h2 id="DefaultBehaviourForUndefinedMethods">Default behaviour for undefined methods</h2>
+
+When an undefined method is called an exception is normally raised. However this behviour can be overridden by supplying a stub object to the <code>Mock</code> instance's <code>set_default_stub</code> method.
+
+<pre>
+    mock.set_default_stub(pmock.return_value("legs"))
+    mock.crazy()
+</pre>
+
+<h2 id="FromImports">From imports</h2>
+
+The test code can be made more concise by importing the pmock module's public classes and functions into the test module.
+
+<pre>
+    from pmock import *
+
+    mock = Mock()
+    mock.expects(once()).calculate(eq(34), eq(2)).will(return_value(68))
+</pre>
+
+<h2 id="TestBaseClass">Test base class</h2>
+
+The <code>MockTestCase</code> class is a convenience base class for tests. It provides the <code>mock</code> method for creating mock objects that will be automatically verified after the test method has run. The verify calls are considered to be part of the test and so are made to the mock object before <code>tearDown</code> has been called.
+
+<pre>
+    class FooTest(pmock.MockTestCase):
+
+        def test_involving_mocks(self):
+            bar = self.mock()
+            bar.expects(pmock.once()).baz()
+            qux.quux(bar)
+            # no need for verify call as its done by MockTestCase
+</pre>
+
+<h2 id="FurtherInformation">Further information</h2>
+
+<p>Looking at the pMock <a href="http://cvs.sourceforge.net/viewcvs.py/pmock/pmock/src/acceptance_tests.py">acceptance tests</a> may be helpful in further clarifying the behaviour of the module.</p>
+
+<p>The <a href="http://www.mockobjects.com">mock objects</a> and <a href="http://www.jmock.org">jmock</a> websites contain useful information on mock objects and their use as a testing technique.</p>
+
+<p>Martin Fowler has written an <a href="http://martinfowler.com/articles/mocksArentStubs.html">interesting article about mock objects</a> and the style of unit testing that uses them.</p>
+
+<p>Nat Pryce, one of the jmock authors, has written <a href="http://nat.truemesh.com/archives/000342.html">a response</a> to Martin Fowler's article.</p>
+
+</body>
+</html>
+"""Show some test errors generated by pmock"""
+
+from pmock import *
+import unittest
+
+
+class ErrorsTest(unittest.TestCase):
+
+    def test_unsatisfied_expectation(self):
+        mock = Mock()
+        mock.expects(once()).foo()
+        mock.verify()
+
+    def test_unexpected_call(self):
+        mock = Mock()
+        mock.foo()
+
+    def test_conflicting_call(self):
+        mock = Mock()
+        mock.expects(never()).foo()
+        mock.foo()
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+
+
+    
+import unittest
+
+from pmock import *
+
+
+class SystemError(Exception):
+
+    def __init__(self, msg):
+        self.msg = msg
+
+
+class Greeting:
+
+    def __init__(self, system):
+        self._system = system
+
+    def message(self):
+        try:
+            (hours, seconds) = self._system.time()
+            if hours < 12:
+                return "Good morning"
+            elif hours >= 12 and hours < 19:
+                return "Good afternoon"
+            else:
+                return "Good evening"
+        except SystemError, err:
+            self._system.log("time problem: %s" % err.msg)
+            return "Good day"
+
+
+class GreetingTest(MockTestCase):
+
+    def setUp(self):
+        self.system = self.mock()
+        self.greeting = Greeting(self.system)
+
+    def test_afternoon(self):
+        self.system.expects(once()).time().will(return_value((12,10)))
+        self.assertEqual(self.greeting.message(), "Good afternoon")
+
+    def test_morning(self):
+        self.system.expects(once()).time().will(return_value((6,50)))
+        self.assertEqual(self.greeting.message(), "Good morning")
+
+    def test_evening(self):
+        self.system.expects(once()).time().will(return_value((19,50)))
+        self.assertEqual(self.greeting.message(), "Good evening")
+
+    def test_clock_failure(self):
+        err_msg = "bzzz..malfunction"
+        err = SystemError(err_msg)
+        self.system.expects(once()).time().will(raise_exception(err))
+        self.system.expects(once()).log(string_contains(err_msg))
+        self.assertEqual(self.greeting.message(), "Good day")
+
+
+if __name__ == "__main__":
+    unittest.main()
+    
+        
+                                                
+"""pMock: Python mock object framework.
+
+pMock provides support for creating mock objects for use in unit testing.
+The api is modelled on the jmock mock object framework.
+"""
+
+classifiers = """\
+Development Status :: 3 - Alpha
+Intended Audience :: Developers
+License :: OSI Approved :: Python Software Foundation License
+Programming Language :: Python
+Topic :: Software Development :: Libraries :: Python Modules
+Topic :: Software Development :: Testing
+Operating System :: OS Independent
+"""
+
+from distutils.core import setup
+
+doclines = __doc__.split("\n")
+
+setup (
+    name = "pmock",
+    version = "0.3",
+    maintainer="Graham Carlyle",
+    maintainer_email="grahamcarlyle@users.sourceforge.net",
+    license="Same terms as Python",
+    platforms = ["any"],
+    url = "http://pmock.sf.net",
+    description = doclines[0],
+    classifiers = filter(None, classifiers.split("\n")),
+    long_description = "\n".join(doclines[2:]),
+    package_dir = {"": "src"},
+    py_modules = ["pmock"]
+    )

src/acceptance_tests.py

+import unittest
+
+import pmock
+import testsupport
+
+
+class MockMethodTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog")
+        
+    def test_uncalled_method(self):
+        try:
+            self.mock.verify()
+            self.fail()
+        except pmock.VerificationError:
+            pass
+
+    def test_called_method(self):
+        self.mock.proxy().dog()
+        self.mock.verify()
+
+    def test_called_method_with_extra_arg(self):
+        self.mock.proxy().dog("bone")
+        self.mock.verify()
+
+    def test_call_wrong_method(self):
+        try:
+            self.mock.proxy().cat()
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+    def test_default_return_value(self):
+        self.assertEqual(self.mock.proxy().dog(), None)
+
+    def test_called_method_twice(self):
+        self.mock.proxy().dog()
+        try:
+            self.mock.proxy().dog()
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class MockMethodArgTestMixin(object):
+
+    def test_uncalled_method(self):
+        try:
+            self.mock.verify()
+            self.fail()
+        except pmock.VerificationError:
+            pass
+
+    def test_method_with_correct_arg(self):
+        self.mock.proxy().dog("bone")
+        self.mock.verify()
+
+    def test_call_method_with_incorrect_arg(self):
+        try:
+            self.mock.proxy().dog("carrot")
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+    def test_call_method_with_insufficient_args(self):
+        try:
+            self.mock.proxy().dog()
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+    def test_method_with_correct_arg_and_extras(self):
+        self.mock.proxy().dog("bone", "biscuit")
+        self.mock.verify()
+
+
+class MockMethodWithArgTest(MockMethodArgTestMixin, unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog").with(pmock.eq("bone"))
+
+    def test_method_with_correct_arg_and_extras(self):
+        try:
+            self.mock.proxy().dog("bone", "biscuit")
+        except pmock.MatchError:
+            pass
+
+
+class MockMethodWithAtLeastArgTest(MockMethodArgTestMixin, unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog").with_at_least(
+            pmock.eq("bone"))
+
+    def test_method_with_correct_arg_and_extras(self):
+        self.mock.proxy().dog("bone", "biscuit")
+        self.mock.verify()
+
+
+class MockMethodWithArgsTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.toys = ["ball", "stick"]
+        self.mock.expects(pmock.once()).method("dog").with(
+            pmock.eq("bone"),
+            pmock.same(self.toys),
+            pmock.string_contains("slipper"))
+
+    def test_method_with_correct_args(self):
+        self.mock.proxy().dog("bone", self.toys, "bob's slipper")
+        self.mock.verify()
+
+    def test_call_method_with_insufficient_args(self):
+        try:
+            self.mock.proxy().dog("bone", "biscuit")
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class MockMethodKeywordArgTestMixin(object):
+    
+    def test_uncalled_method(self):
+        try:
+            self.mock.verify()
+            self.fail()
+        except pmock.VerificationError:
+            pass
+
+    def test_method_with_correct_arg(self):
+        self.mock.proxy().dog(food="bone")
+        self.mock.verify()
+
+    def test_call_method_with_incorrect_arg(self):
+        try:
+            self.mock.proxy().dog(food="ball")
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+    def test_call_method_with_missing_arg(self):
+        try:
+            self.mock.proxy().dog(toy="ball")
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class MockMethodWithKeywordArgTest(MockMethodKeywordArgTestMixin,
+                                   unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog").with(
+            food=pmock.eq("bone"))
+
+    def test_method_with_correct_arg_and_extra(self):
+        try:
+            self.mock.proxy().dog(toy="ball", food="bone")
+        except pmock.MatchError:
+            pass
+
+
+class MockMethodWithAtLeastKeywordArgTest(MockMethodKeywordArgTestMixin,
+                                          unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog").with_at_least(
+            food=pmock.eq("bone"))
+
+    def test_method_with_correct_arg_and_extra(self):
+        self.mock.proxy().dog(toy="ball", food="bone")
+        self.mock.verify()
+
+
+class MockMethodWithNoArgsTestMixin(object):
+
+    def test_method_with_no_args(self):
+        self.mock.proxy().dog()
+        self.mock.verify()
+
+    def test_method_with_args(self):
+        try:
+            self.mock.proxy().dog("biscuit")
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+    def test_method_with_kwargs(self):
+        try:
+            self.mock.proxy().dog(toy="ball")
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class MockMethodWithNoArgsTest(MockMethodWithNoArgsTestMixin,
+                               unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog").no_args()
+
+
+class MockMethodWithAnyArgsTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog").any_args()
+
+    def test_method_with_no_args(self):
+        self.mock.proxy().dog()
+        self.mock.verify()
+
+    def test_method_with_args(self):
+        self.mock.proxy().dog("biscuit")
+        self.mock.verify()
+        
+    def test_method_with_kwargs(self):
+        self.mock.proxy().dog(toy="ball")
+        self.mock.verify()
+        
+
+class MockMethodWillTest(unittest.TestCase):
+
+    def test_method_will_return_value(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("dog").will(
+            pmock.return_value("bone"))
+        self.assertEqual(self.mock.proxy().dog(), "bone")
+
+    def test_method_will_raise_exception(self):
+        self.mock = pmock.Mock()
+        custom_err = RuntimeError()
+        self.mock.expects(pmock.once()).method("dog").will(
+            pmock.raise_exception(custom_err))
+        try:
+            self.mock.proxy().dog()
+            self.fail()
+        except RuntimeError, err:
+            self.assert_(err is custom_err)
+            self.mock.verify()
+
+
+class MockDirectMethodWithNoArgsTest(MockMethodWithNoArgsTestMixin,
+                                     unittest.TestCase):
+    
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).dog()
+
+
+class MockDirectMethodAdditionalTest(unittest.TestCase):
+
+    def test_expectation(self):
+        mock = pmock.Mock()
+        mock.expects(pmock.once()).dog(
+            pmock.eq("bone"), food=pmock.eq("biscuit")).will(
+            pmock.return_value("bark"))
+        self.assert_(mock.proxy().dog("bone", food="biscuit"), "bark")
+            
+    
+class MockMultipleMethodsTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("cat")
+        self.mock.expects(pmock.once()).method("cat").with(pmock.eq("mouse"))
+
+    def test_method_lifo_order(self):
+         self.mock.proxy().cat("mouse")
+         self.mock.proxy().cat()
+         self.mock.verify()
+
+    def test_uncalled_method(self):
+        self.mock.proxy().cat()
+        try:
+            self.mock.verify()
+            self.fail()
+        except pmock.VerificationError:
+            pass
+
+
+class SpecialMethodsTest(pmock.MockTestCase):
+
+    def test_expected_specials(self):
+        class Test(pmock.MockTestCase):
+            def test_method(self):
+                self.special = self.mock()
+                self.special.expects(pmock.once()).__cmp__(pmock.eq("guppy")).\
+                    will(pmock.return_value(0))
+                self.special.expects(pmock.once()).__call__(pmock.eq("blub"),
+                                                            pmock.eq("blub"))
+                self.special == "guppy"
+                self.special("blub", "blub")
+        test = Test('test_method')
+        result = unittest.TestResult()
+        test(result)
+        self.assertEqual(len(result.failures), 0)
+        self.assertEqual(len(result.errors), 0)
+
+    def test_unexpected_specials(self):
+        class Test(pmock.MockTestCase):
+            def test_method(self):
+                self.special = self.mock()
+                self.special == "guppy"
+        test = Test('test_method')
+        result = unittest.TestResult()
+        test(result)
+        self.assertEqual(len(result.failures), 1)
+        self.assertEqual(len(result.errors), 0)
+
+
+class CallMockDirectlyTest(unittest.TestCase):
+
+    def test_call_mock_rather_than_proxy(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("newt")
+        self.mock.newt()
+        self.mock.verify()
+
+
+class FifoExpectationTest(unittest.TestCase):
+
+    def test_method_fifo_order(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("cat").with(pmock.eq("mouse"))
+        self.mock.expects(pmock.once()).method("cat")
+        self.mock.proxy().cat(food="mouse")
+        try:
+            self.mock.proxy().cat()
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class OnceTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("rabbit")
+
+    def test_uncalled(self):
+        try:
+            self.mock.verify()
+        except pmock.VerificationError:
+            pass
+
+    def test_call_once(self):
+        self.mock.proxy().rabbit()
+        self.mock.verify()
+
+    def test_call_too_many(self):
+        self.mock.proxy().rabbit()
+        try:
+            self.mock.proxy().rabbit()
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class AtLeastOnceTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.at_least_once()).method("rabbit")
+
+    def test_uncalled(self):
+        try:
+            self.mock.verify()
+        except pmock.VerificationError:
+            pass
+
+    def test_call_once(self):
+        self.mock.proxy().rabbit()
+        self.mock.verify()
+
+    def test_call_many(self):
+        self.mock.proxy().rabbit()
+        self.mock.proxy().rabbit()
+        self.mock.proxy().rabbit()
+        self.mock.proxy().rabbit()
+        self.mock.verify()
+
+
+class NeverTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.never()).method("rabbit")
+
+    def test_uncalled(self):
+        self.mock.verify()
+
+    def test_called(self):
+        try:
+            self.mock.proxy().rabbit()
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class OrderedCallsBasicTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+        self.mock.expects(pmock.once()).method("bull").id("bull call")
+        self.mock.expects(pmock.once()).method("cow").after("bull call")
+
+    def test_call_in_order(self):
+        self.mock.proxy().bull()
+        self.mock.proxy().cow()
+        self.mock.verify()
+
+    def test_call_out_of_order_doesnt_match(self):
+        try:
+            self.mock.proxy().cow()
+            self.fail()
+        except pmock.MatchError:
+            pass
+            
+
+class OrderedCallsAcrossMocksTest(unittest.TestCase):
+
+    def setUp(self):
+        self.mock1 = pmock.Mock("field")
+        self.mock2 = pmock.Mock()
+        self.mock1.expects(pmock.once()).method("bull").id("bovine")
+        self.mock2.expects(pmock.once()).method("cow").after("bovine",
+                                                             self.mock1)
+
+    def test_call_in_order(self):
+        self.mock1.proxy().bull()
+        self.mock2.proxy().cow()
+        self.mock1.verify()
+        self.mock2.verify()
+        
+    def test_call_out_of_order_doesnt_match(self):
+        try:
+            self.mock2.proxy().cow()
+            self.fail()
+        except pmock.MatchError:
+            pass
+
+
+class OrderedCallsAdditionalTest(testsupport.ErrorMsgAssertsMixin,
+                                 unittest.TestCase):
+
+    def setUp(self):
+        self.mock = pmock.Mock()
+
+    def test_method_name_as_id(self):
+        self.mock.expects(pmock.once()).method("bull")
+        self.mock.expects(pmock.once()).method("cow").after("bull")
+        self.mock.proxy().bull()
+        self.mock.proxy().cow()
+        self.mock.verify()
+
+    def test_method_name_as_id_binds_to_last_matching_expectation(self):
+        self.mock.expects(pmock.once()).method("cow").with(pmock.eq("moo"))
+        self.mock.expects(pmock.once()).method("cow").with(pmock.eq("mooo"))
+        self.mock.expects(pmock.once()).method("bull").after("cow")
+        self.mock.proxy().cow("mooo")
+        self.mock.proxy().bull()
+        self.mock.proxy().cow("moo")
+        self.mock.verify()
+
+    def test_after_undefined_id_raises(self):
+        try:
+            self.mock.expects(pmock.once()).method("cow").after("ox")
+            self.fail()
+        except pmock.DefinitionError, err:
+            self.assertUndefinedIdMsg(err.msg, "ox")
+
+    def test_disallow_duplicate_ids(self):
+        self.mock.expects(pmock.once()).method("cow").id("bovine")
+        try:
+            self.mock.expects(pmock.once()).method("bull").id("bovine")
+            self.fail()
+        except pmock.DefinitionError, err:
+            self.assertDuplicateIdMsg(err.msg, "bovine")
+
+    def test_disallow_duplicating_id_of_existing_method(self):
+        self.mock.expects(pmock.once()).method("cow")
+        try:
+            self.mock.expects(pmock.once()).method("bovine").id("cow")
+            self.fail()
+        except pmock.DefinitionError, err:
+            self.assertDuplicateIdMsg(err.msg, "cow")
+
+
+class StubTest(unittest.TestCase):
+
+    def test_specified_like_expectations(self):
+        mock = pmock.Mock()
+        mock.stubs().method("fox")
+        mock.stubs().method("fox").with_at_least("sly")
+        mock.stubs().method("fox").with("sly", meal="chicken")
+        mock.stubs().method("fox").will(pmock.return_value("trot"))
+        self.assertEqual(mock.proxy().fox(), "trot")
+        mock.fox("sly", meal="chicken")
+        mock.fox("sly")
+        mock.fox()
+
+    def test_uninvoked_doesnt_raise_verify(self):
+        mock = pmock.Mock()
+        mock.stubs().method("fox")
+        mock.verify()
+
+    def test_expectation_can_use_for_ordering(self):
+        mock = pmock.Mock()
+        mock.stubs().method("fox")
+        mock.expects(pmock.once()).method("farmer").after("fox")
+        mock.fox()
+        mock.farmer()
+
+    def test_set_default_stub(self):
+        mock = pmock.Mock()
+        mock.set_default_stub(pmock.return_value("trot"))
+        self.assertEqual(mock.fox(), "trot")
+
+
+class ErrorMessageTest(unittest.TestCase):
+
+    def test_expected_method_not_invoked(self):
+        mock = pmock.Mock()
+        mock.expects(pmock.once()).ant()
+        try:
+            mock.verify()
+        except pmock.VerificationError, err:
+            self.assertEqual(
+                err.msg,
+                "expected method was not invoked: expected once: ant()")
+
+    def test_unmatched_method(self):
+        mock = pmock.Mock()
+        mock.stubs().mite(looks=pmock.eq("creepy"))
+        mock.expects(pmock.once()).termite()
+        mock.termite()
+        try:
+            mock.ant()
+        except pmock.MatchError, err:
+            self.assertEqual(err.msg,
+                             "no match found\n"
+                             "invoked ant()\n"
+                             "in:\n"
+                             "stub: mite(looks=pmock.eq('creepy')),\n"
+                             "expected once and has been invoked: termite()")
+
+    def test_conflicting_method(self):
+        mock = pmock.Mock()
+        mock.expects(pmock.never()).cockroach()
+        try:
+            mock.cockroach()
+        except pmock.MatchError, err:
+            self.assertEqual(err.msg,
+                             "expected method to never be invoked\n"
+                             "invoked cockroach()\n"
+                             "in:\n"
+                             "expected not to be called: cockroach()")
+
+
+class MockTestCaseTest(unittest.TestCase):
+
+    def test_verify_unsatisfied_expectation(self):
+        class Test(pmock.MockTestCase):
+            def test_method(self):
+                mock = self.mock()
+                mock.expects(pmock.once()).crow()
+        test = Test('test_method')
+        result = unittest.TestResult()
+        test(result)
+        self.assertEqual(len(result.failures), 1)
+        self.assertEqual(len(result.errors), 0)
+        traceback = result.failures[0][1]
+        self.assert_(traceback.find('VerificationError') != -1)
+
+    def test_verify_satisfied_expectation(self):
+        class Test(pmock.MockTestCase):
+            def test_method(self):
+                mock = self.mock()
+                mock.expects(pmock.once()).crow()
+                mock.crow()
+        test = Test('test_method')
+        result = unittest.TestResult()
+        test(result)
+        self.assertEqual(len(result.failures), 0)
+        self.assertEqual(len(result.errors), 0)
+
+        
+if __name__ == '__main__':
+    unittest.main()
+"""
+Python mock object framework, providing support for creating mock
+objects for use in unit testing.
+
+The api is modelled on the jmock mock object framework.
+
+Usage::
+
+    import pmock
+    import unittest
+
+    class PowerStation(object):
+        def start_up(self, reactor):
+            try:
+                reactor.activate('core')
+            except Exception, err:
+                reactor.shutdown()
+
+    class PowerStationTestCase(unittest.TestCase):
+        def test_successful_activation(self):
+            mock = pmock.Mock()
+            mock.expects(pmock.once()).activate(pmock.eq('core'))
+            PowerStation().start_up(mock)
+            mock.verify()
+        def test_problematic_activation(self):
+            mock = pmock.Mock()
+            mock.expects(pmock.once()).activate(pmock.eq('core')).will(
+                pmock.raise_exception(RuntimeError('overheating')))
+            mock.expects(pmock.once()).shutdown()
+            PowerStation().start_up(mock)
+            mock.verify()
+
+    if __name__ == '__main__':
+        unittest.main()
+
+Further information is available in the bundled documentation, and from
+http://pmock.sourceforge.net/
+
+Copyright (c) 2004, Graham Carlyle
+
+This module is free software, and you may redistribute it and/or modify
+it under the same terms as Python itself, so long as this copyright message
+and disclaimer are retained in their original form.
+ 
+IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+ 
+THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+"""
+
+__author__ = "Graham Carlyle"
+__email__ = "grahamcarlyle at users dot sourceforge dot net"
+__version__ = "0.3"
+
+import unittest
+
+##############################################################################
+# Exported classes and functions
+##############################################################################
+
+__all__ = ["Mock", "MockTestCase",
+           "once", "at_least_once", "never",
+           "eq", "same", "string_contains", "functor",
+           "return_value", "raise_exception"]
+
+
+##############################################################################
+# Mock objects framework
+##############################################################################
+
+class Error(AssertionError):
+
+    def __init__(self, msg):
+        AssertionError.__init__(self, msg)
+        self.msg = msg
+
+    def _mockers_str(cls, mockers):
+        mockers_strs = [str(mocker) for mocker in mockers]
+        return ", ".join(mockers_strs)
+
+    _mockers_str = classmethod(_mockers_str)
+
+
+class VerificationError(Error):
+    """An expectation have failed verification."""
+    
+    def create_error(cls, msg, verified_invokable):
+        err_msg = "%s: %s" % (msg, verified_invokable)
+        return VerificationError(err_msg)
+
+    create_error = classmethod(create_error)
+
+
+class MatchError(Error):
+    """Method call unexpected."""
+    
+    def create_error(cls, msg, invocation, mock):
+        err_msg = "%s\ninvoked %s" % (msg, invocation)
+        invokables_str = mock.invokables_str()
+        if invokables_str != "":
+            err_msg += "\nin:\n" + invokables_str
+        return MatchError(err_msg)
+
+    create_error = classmethod(create_error)
+    
+
+class DefinitionError(Error):
+    """Expectation definition isn't valid."""
+
+    def create_unregistered_id_error(cls, unregistered_id):
+        msg = "reference to undefined id: %s" % unregistered_id
+        return DefinitionError(msg)
+
+    create_unregistered_id_error = classmethod(
+        create_unregistered_id_error)
+
+    def create_duplicate_id_error(cls, builder_id):
+        msg = "id: %s is already defined" % builder_id
+        return DefinitionError(msg)
+
+    create_duplicate_id_error = classmethod(create_duplicate_id_error)
+
+
+class InvocationMocker(object):
+    
+    def __init__(self, invocation_matcher):
+        self._matchers = []
+        self._invocation_matcher = invocation_matcher
+        self._matchers.append(invocation_matcher)
+        self._stub = None
+        self._id = None
+
+    def __str__(self):
+        strs = ["%s: " % str(self._invocation_matcher)]
+        for matcher in self._matchers[1:]:
+            strs.append(str(matcher))
+        if self._stub is not None:
+            strs.append(", %s" % self._stub)
+        if self._id is not None:
+            strs.append(" [%s]" % self._id)
+        return "".join(strs)
+
+    def add_matcher(self, matcher):
+        self._matchers.append(matcher)
+
+    def set_stub(self, stub):
+        self._stub = stub
+
+    def invoke(self, invocation):
+        for matcher in self._matchers:
+            matcher.invoked(invocation)
+        if self._stub is not None:
+            return self._stub.invoke(invocation)
+
+    def matches(self, invocation):
+        for matcher in self._matchers:
+            if not matcher.matches(invocation):
+                return False
+        return True
+
+    def set_id(self, mocker_id):
+        self._id = mocker_id
+
+    def verify(self):
+        try:
+            for matcher in self._matchers:
+                matcher.verify()
+        except AssertionError, err:
+            raise VerificationError.create_error(str(err), self)
+
+
+class AbstractArgumentsMatcher(object):
+
+    def __init__(self, arg_constraints=(), kwarg_constraints={}):
+        self._arg_constraints = arg_constraints
+        self._kwarg_constraints = kwarg_constraints
+
+    def _arg_strs(self):
+        arg_strs = [str(c) for c in self._arg_constraints]
+        keywords = self._kwarg_constraints.keys()
+        keywords.sort()
+        for kw in keywords:
+            constraint = self._kwarg_constraints[kw]
+            arg_strs.append("%s=%s" % (kw, str(constraint)))
+        return arg_strs
+
+    def _matches_args(self, invocation):
+        for i, constraint in enumerate(self._arg_constraints):
+            if not constraint.eval(invocation.args[i]):
+                return False
+        return True
+
+    def _matches_kwargs(self, invocation):
+        for kw, constraint in self._kwarg_constraints.iteritems():
+            if (not invocation.kwargs.has_key(kw) or
+                not constraint.eval(invocation.kwargs[kw])):
+                return False
+        return True
+
+    def matches(self, invocation):
+        return (self._matches_args(invocation) and
+                self._matches_kwargs(invocation))
+
+    def invoked(self, invocation):
+        pass
+
+    def verify(self):
+        pass
+
+
+class LeastArgumentsMatcher(AbstractArgumentsMatcher):
+
+    def __str__(self):
+        arg_strs = AbstractArgumentsMatcher._arg_strs(self)
+        arg_strs.append("...")
+        return "(%s)" % ", ".join(arg_strs)
+
+    def _matches_args(self, invocation):
+        if len(self._arg_constraints) > len(invocation.args):
+            return False
+        return AbstractArgumentsMatcher._matches_args(self, invocation)
+
+
+ANY_ARGS_MATCHER = LeastArgumentsMatcher()
+
+
+class AllArgumentsMatcher(AbstractArgumentsMatcher):
+
+    def __str__(self):
+        return "(%s)" % ", ".join(AbstractArgumentsMatcher._arg_strs(self))
+        
+    def _matches_args(self, invocation):
+        if len(self._arg_constraints) != len(invocation.args):
+            return False
+        return AbstractArgumentsMatcher._matches_args(self, invocation)
+
+    def _matches_kwargs(self, invocation):
+        for invocation_kw in invocation.kwargs.iterkeys():
+            if invocation_kw not in self._kwarg_constraints:
+                return False
+        return AbstractArgumentsMatcher._matches_kwargs(self, invocation)
+
+
+NO_ARGS_MATCHER = AllArgumentsMatcher()
+
+
+class MethodMatcher(object):
+
+    def __init__(self, name):
+        self._name = name
+
+    def __str__(self):
+         return self._name
+
+    def matches(self, invocation):
+        return invocation.name == self._name
+
+    def invoked(self, invocation):
+        pass
+
+    def verify(self):
+        pass
+
+
+class InvokedAfterMatcher(object):
+
+    def __init__(self, invocation_recorder, description):
+        self._invocation_recorder = invocation_recorder
+        self._description = description
+        
+    def __str__(self):
+        return ".after(%s)" % self._description
+
+    def matches(self, invocation):
+        return self._invocation_recorder.has_been_invoked()
+
+    def invoked(self, invocation):
+        pass
+
+    def verify(self):
+        pass
+
+
+class InvocationMockerBuilder(object):
+
+    def __init__(self, mocker, builder_namespace):
+        self._mocker = mocker
+        self._builder_namespace = builder_namespace
+
+    def __call__(self, *arg_constraints, **kwarg_constraints):
+        self._mocker.add_matcher(AllArgumentsMatcher(arg_constraints,
+                                                     kwarg_constraints))
+        return self
+
+    def __getattr__(self, name):
+        """Define method name directly."""
+        self._mocker.add_matcher(MethodMatcher(name))
+        self._builder_namespace.register_method_name(name, self)
+        return self
+
+    def method(self, name):
+        """Define method name."""
+        self._mocker.add_matcher(MethodMatcher(name))
+        self._builder_namespace.register_method_name(name, self)
+        return self
+
+    def with(self, *arg_constraints, **kwarg_constraints):
+        """Fully specify the method's arguments."""
+        self._mocker.add_matcher(AllArgumentsMatcher(arg_constraints,
+                                                     kwarg_constraints))
+        return self
+
+    def with_at_least(self, *arg_constraints, **kwarg_constraints):
+        """Specify the method's minimum required arguments."""
+        self._mocker.add_matcher(LeastArgumentsMatcher(arg_constraints,
+                                                       kwarg_constraints))
+        return self
+
+    def any_args(self):
+        """Method takes any arguments."""
+        self._mocker.add_matcher(ANY_ARGS_MATCHER)
+        return self
+
+    def no_args(self):
+        """Method takes no arguments."""
+        self._mocker.add_matcher(NO_ARGS_MATCHER)
+        return self
+
+    def will(self, stub):
+        """Set stub when method is called."""
+        self._mocker.set_stub(stub)
+        return self
+
+    def id(self, id_str):
+        """Define a id for use in other mock's L{after} method."""
+        self._mocker.set_id(id_str)
+        self._builder_namespace.register_unique_id(id_str, self)
+        return self
+
+    def after(self, id_str, other_mock=None):
+        """Expected to be called after the method with supplied id."""
+        if other_mock is not None:
+            builder_namespace = other_mock
+            description = "%s on mock %s" % (repr(id_str),
+                                             repr(other_mock.get_name()))
+        else:
+            builder_namespace = self._builder_namespace
+            description = repr(id_str)
+        builder = builder_namespace.lookup_id(id_str)
+        if builder is None:
+            raise DefinitionError.create_unregistered_id_error(id_str)
+        invocation_recorder = InvokedRecorderMatcher()
+        builder.match(invocation_recorder)
+        matcher = InvokedAfterMatcher(invocation_recorder, description)
+        self._mocker.add_matcher(matcher)
+        return self
+
+    def match(self, matcher):
+        self._mocker.add_matcher(matcher)
+        return self
+
+
+class Invocation(object):
+
+    def __init__(self, name, args, kwargs):
+        self.name = name
+        self.args = args
+        self.kwargs = kwargs
+
+    def __str__(self):
+        arg_strs = [repr(arg) for arg in self.args]
+        keywords = self.kwargs.keys()
+        keywords.sort()
+        for kw in keywords:
+            arg_strs.append("%s=%s" % (kw, repr(self.kwargs[kw])))
+        return "%s(%s)" % (self.name, ", ".join(arg_strs))
+
+
+class BoundMethod(object):
+
+    def __init__(self, name, mock):
+        self._name = name
+        self._mock = mock
+
+    def __call__(self, *args, **kwargs):
+        return self._mock.invoke(Invocation(self._name, args, kwargs))
+
+
+class DefaultStub(object):
+
+    def invoke(self, invocation):
+        raise AssertionError("no match found")
+
+_DEFAULT_STUB = DefaultStub()
+
+
+def _special(method_name):
+    def mocked_special(self, *args, **kwargs):
+        return self._invoke_special(Invocation(method_name, args, kwargs))
+    return mocked_special
+
+
+class SpecialsMock(object):
+
+    __call__ = _special("__call__")
+    __cmp__ = _special("__cmp__")
+    # assume no good reason to mock __del__
+    __delattr__ = _special("__delattr__")
+    # __eq__, __ne__, etc. comparison operators covered by __cmp__
+    # __getattr__ & __getattribute__ needed for implementation
+    __hash__ = _special("__hash__")
+    # __init__ & __new__ needed for implementation
+    __nonzero__ = _special("__nonzero__")
+    __repr__ = _special("__repr__")
+    # assume no good reason to mock __setattr__
+    __str__ = _special("__str__")
+    # __unicode__ available if __str__ defined
+
+
+class Proxy(SpecialsMock):
+    """A proxy for a mock object."""
+    
+    def __init__(self, mock):
+        self._mock = mock
+
+    def __getattr__(self, attr_name):
+        return BoundMethod(attr_name, self._mock)
+
+    def _invoke_special(self, invocation):
+        return self._mock._invoke_special(invocation)
+
+
+def mock_str(mock):
+    return "<pmock.Mock id=%s>" % id(mock)
+
+
+class Mock(SpecialsMock):
+    """A mock object."""
+
+    def __init__(self, name=None):
+        self._name = name
+        self._invokables = []
+        self._proxy = Proxy(self)
+        self._default_stub = _DEFAULT_STUB
+        self._id_table = {}
+
+    def __getattr__(self, attr_name):
+        return BoundMethod(attr_name, self)
+
+    def get_name(self):
+        if self._name is not None:
+            return self._name
+        else:
+            return mock_str(self)
+
+    def _get_match_order_invokables(self):
+        return self._invokables[::-1] # LIFO
+
+    def lookup_id(self, builder_id):
+        return self._id_table.get(builder_id, None)
+
+    def register_unique_id(self, builder_id, builder):
+        if self._id_table.has_key(builder_id):
+            raise DefinitionError.create_duplicate_id_error(builder_id)
+        self._id_table[builder_id] = builder
+
+    def register_method_name(self, builder_id, builder):
+        self._id_table[builder_id] = builder
+        
+    def invoke(self, invocation):
+        try:
+            matching_invokable = None
+            for invokable in self._get_match_order_invokables():
+                if invokable.matches(invocation):
+                    return invokable.invoke(invocation)
+            return self._default_stub.invoke(invocation)
+        except AssertionError, err:
+            raise MatchError.create_error(str(err), invocation, self)
+
+    def _invoke_special(self, invocation):
+        return self.invoke(invocation)
+            
+    def add_invokable(self, invokable):
+        self._invokables.append(invokable)
+
+    def invokables_str(self):
+        invokable_strs = [str(invokable) for invokable in self._invokables]
+        return ",\n".join(invokable_strs)
+
+    def expects(self, invocation_matcher):
+        """Define an expectation for a method.
+
+        @return: L{InvocationMocker}
+        """
+        mocker = InvocationMocker(invocation_matcher)
+        self.add_invokable(mocker)
+        return InvocationMockerBuilder(mocker, self)
+
+    def stubs(self):
+        """Define a method that may or may not be called.
+
+        @return: L{InvocationMocker}
+        """
+        mocker = InvocationMocker(_STUB_MATCHER_INSTANCE)
+        self.add_invokable(mocker)
+        return InvocationMockerBuilder(mocker, self)
+
+    def set_default_stub(self, stub):
+        """Set the default behaviour of undefined methods."""
+        self._default_stub = stub
+        
+    def proxy(self):
+        """Return a proxy to the mock object.
+
+        Proxies only have the mocked methods which may be useful if the
+        mock's builder methods are in the way.
+        """ 
+        return self._proxy
+    
+    def verify(self):
+        """Check that the mock object has been called as expected."""
+        for invokable in self._get_match_order_invokables():
+            invokable.verify()
+
+
+class MockTestCase(unittest.TestCase):
+
+    def __init__(self, methodName='runTest'):
+        unittest.TestCase.__init__(self, methodName)
+        self._test_method_name = methodName
+        self._mocks = []
+        
+    def _auto_verified_test(self):
+        self._real_test_method()
+        for mock in self._mocks:
+            mock.verify()
+    
+    def __call__(self, result=None):
+        self._mocks = []
+        self._real_test_method = getattr(self, self._test_method_name)
+        setattr(self, self._test_method_name, self._auto_verified_test)
+        unittest.TestCase.__call__(self, result)
+        setattr(self, self._test_method_name, self._real_test_method)
+
+    def mock(self):
+        """Create a mock object that will be automatically verified
+        after the test is run.
+        """
+        mock = Mock()
+        self._mocks.append(mock)
+        return mock
+
+
+##############################################################################
+# Mocked method stubs
+############################################################################## 
+
+class ReturnValueStub(object):
+    
+    def __init__(self, value):
+        self._value = value
+
+    def __str__(self):
+        return "returns %s" % repr(self._value)
+
+    def invoke(self, invocation):
+        return self._value
+
+
+def return_value(value):
+    """Stub that returns the supplied value.    
+
+    Convenience function for creating a L{ReturnValueStub} instance.
+    """
+    return ReturnValueStub(value)
+
+
+class RaiseExceptionStub(object):
+
+    def __init__(self, exception):
+        self._exception = exception
+
+    def __str__(self):
+        return "raises %s" % self._exception
+
+    def invoke(self, invocation):
+        raise self._exception
+
+
+def raise_exception(exception):
+    """Stub that raises the supplied exception.    
+
+    Convenience function for creating a L{RaiseExceptionStub} instance.
+    """
+    return RaiseExceptionStub(exception)
+
+
+##############################################################################
+# Invocation matchers
+############################################################################## 
+
+class InvokedRecorderMatcher(object):
+
+    def __init__(self):
+        self._invoked = False
+
+    def has_been_invoked(self):
+        return self._invoked
+    
+    def matches(self, invocation):
+        return True
+
+    def invoked(self, invocation):
+        self._invoked = True
+
+    def verify(self):
+        pass
+
+    
+class OnceInvocationMatcher(InvokedRecorderMatcher):
+
+    def __str__(self):
+        if self.has_been_invoked():
+            return "expected once and has been invoked"
+        else:
+            return "expected once"
+    
+    def matches(self, invocation):
+        return not self.has_been_invoked()
+
+    def verify(self):
+        if not self.has_been_invoked():
+            raise AssertionError("expected method was not invoked")
+
+
+def once():
+    """Method will be called only once.
+
+    Convenience function for creating a L{OnceInvocationMatcher} instance.
+    """
+    return OnceInvocationMatcher()
+
+
+class AtLeastOnceInvocationMatcher(InvokedRecorderMatcher):
+
+    def __str__(self):
+        if self.has_been_invoked():
+            return "expected at least once and has been invoked"
+        else:
+            return "expected at least once"
+
+    def matches(self, invocation):
+        return True
+
+    def verify(self):
+        if not self.has_been_invoked():
+            raise AssertionError("expected method was not invoked")
+
+
+def at_least_once():
+    """Method will be called at least once.
+
+    Convenience function for creating a L{AtLeastOnceInvocationMatcher}
+    instance.
+    """
+    return AtLeastOnceInvocationMatcher()
+
+
+class NotCalledInvocationMatcher(object):
+
+    def __str__(self):
+        return "expected not to be called"
+
+    def invoked(self, invocation):
+        raise AssertionError("expected method to never be invoked")
+
+    def matches(self, invocation):
+        return True
+
+    def verify(self):
+        pass
+
+
+_NOT_CALLED_MATCHER_INSTANCE = NotCalledInvocationMatcher()
+
+
+def never():
+    """Method will not be called.
+
+    Convenience function for getting a L{NotCalledInvocationMatcher} instance.
+    """
+    return _NOT_CALLED_MATCHER_INSTANCE
+
+
+class StubInvocationMatcher(object):
+
+    def __str__(self):
+        return "stub"
+    
+    def invoked(self, invocation):
+        pass
+
+    def matches(self, invocation):
+        return True
+
+    def verify(self):
+        pass
+
+
+_STUB_MATCHER_INSTANCE = StubInvocationMatcher()
+
+
+##############################################################################
+# Argument constraints
+############################################################################## 
+
+class EqConstraint(object):
+
+    def __init__(self, expected):
+        self._expected = expected
+
+    def __repr__(self):
+        return "%s.eq(%s)" % (__name__, repr(self._expected))
+
+    def eval(self, arg):
+        return self._expected == arg
+
+
+def eq(expected):
+    """Argument will be equal to supplied value.
+
+    Convenience function for creating a L{EqConstraint} instance.
+    """
+    return EqConstraint(expected)
+
+
+class SameConstraint(object):
+
+    def __init__(self, expected):
+        self._expected = expected
+
+    def __repr__(self):
+        return "%s.same(%s)" % (__name__, repr(self._expected))
+
+    def eval(self, arg):
+        return self._expected is arg
+
+
+def same(expected):
+    """Argument will be the same as the supplied reference.
+
+    Convenience function for creating a L{SameConstraint} instance.
+    """
+    return SameConstraint(expected)
+
+
+class StringContainsConstraint(object):
+
+    def __init__(self, expected):
+        self._expected = expected
+
+    def __repr__(self):
+        return "%s.string_contains(%s)" % (__name__, repr(self._expected))
+
+    def eval(self, arg):
+        return (arg is not None) and (arg.find(self._expected) != -1)
+
+
+def string_contains(expected):
+    """Argument contains the supplied substring.
+
+    Convenience function for creating a L{StringContainsConstraint} instance.
+    """
+    return StringContainsConstraint(expected)
+
+
+class FunctorConstraint(object):
+
+    def __init__(self, boolean_functor):
+        self._boolean_functor = boolean_functor
+
+    def __repr__(self):
+        return "%s.functor(%s)" % (__name__, repr(self._boolean_functor))
+
+    def eval(self, arg):
+        return self._boolean_functor(arg)
+
+
+def functor(boolean_functor):
+    """Supplied unary function evaluates to True when called with argument.
+
+    Convenience function for creating a L{FunctorConstraint} instance.
+    """
+    return FunctorConstraint(boolean_functor)
+class ErrorMsgAssertsMixin:
+
+    def assertUndefinedIdMsg(self, msg, label):
+        self.assertEqual(msg, "reference to undefined id: %s" % label)
+
+    def assertDuplicateIdMsg(self, msg, builder_id):
+        self.assertEqual(msg, "id: %s is already defined" % builder_id)
+import unittest
+
+import pmock
+import testsupport
+
+
+class VerificationErrorTest(unittest.TestCase):
+
+    def test_create_error(self):
+        class Mocker:
+            def __str__(self): return "matchers"
+        error = pmock.VerificationError.create_error("problem", Mocker())
+        self.assertEqual(error.msg, "problem: matchers")
+
+
+class MatchErrorTest(unittest.TestCase):
+
+    class MockInvocation:
+        def __str__(self): return "call"
+    class Mock:
+        def __init__(self, invokables_str): self._str = invokables_str
+        def invokables_str(self): return self._str
+
+    def test_empty_invokables(self):
+        error = pmock.MatchError.create_error("msg",
+                                              self.MockInvocation(),
+                                              self.Mock(""))
+        self.assertEqual(error.msg, "msg\ninvoked call")
+
+    def test_non_empty_invokables(self):
+        error = pmock.MatchError.create_error("msg",
+                                              self.MockInvocation(),
+                                              self.Mock("invokables"))
+        self.assertEqual(error.msg, "msg\ninvoked call\nin:\ninvokables")
+
+
+class ArgumentsMatcherTestMixin(object):
+
+    def __init__(self, matcher_class):
+        self.matcher_class = matcher_class
+    
+    def test_matches_arguments(self):
+        arg1 = []
+        args_matcher = self.matcher_class((pmock.same(arg1),), {})
+        self.assert_(
+            args_matcher.matches(pmock.Invocation("snake", (arg1,), {})))
+
+    def test_matches_keyword_arguments(self):
+        arg2 = []
+        args_matcher = self.matcher_class((), {"food": pmock.same(arg2)})
+        invocation = pmock.Invocation("snake", (), {"food": arg2})
+        self.assert_(args_matcher.matches(invocation))
+
+    def test_matches_both_types_of_arguments(self):
+        arg1 = []
+        arg2 = []
+        args_matcher = self.matcher_class((pmock.same(arg1),),
+                                          {"food": pmock.same(arg2)})
+        invocation = pmock.Invocation("snake", (arg1,), {"food": arg2})
+        self.assert_(args_matcher.matches(invocation))
+
+    def test_insufficient_arguments(self):
+        args_matcher = self.matcher_class((pmock.eq("slither"),), {})
+        self.assert_(
+            not args_matcher.matches(pmock.Invocation("snake", (), {})))
+
+    def test_insufficient_keyword_arguments(self):
+        args_matcher = self.matcher_class((), {"food": pmock.eq("goat")})
+        self.assert_(
+            not args_matcher.matches(pmock.Invocation("snake", (), {})))
+
+    def test_unmatched_argument(self):
+        class UnmatchedConstraint:
+            def eval(self, invocation): return False
+        args_matcher = self.matcher_class((UnmatchedConstraint(),), {})
+        invocation = pmock.Invocation("snake", ("slither",), {})
+        self.assert_(not args_matcher.matches(invocation))
+
+    def test_unmatched_keyword_argument(self):
+        class UnmatchedConstraint:
+            def eval(self, invocation): return False
+        args_matcher = self.matcher_class((), {"food": UnmatchedConstraint()})
+        invocation = pmock.Invocation("snake", (), {"food": "goat"})
+        self.assert_(not args_matcher.matches(invocation))
+
+
+class AllArgumentsMatcherTest(ArgumentsMatcherTestMixin, unittest.TestCase):
+
+    def __init__(self, *args):
+        ArgumentsMatcherTestMixin.__init__(self, pmock.AllArgumentsMatcher)
+        unittest.TestCase.__init__(self, *args)        
+
+    def test_extra_arguments(self):
+        args_matcher = pmock.AllArgumentsMatcher((pmock.eq("slither"),), {})
+        self.assert_(not args_matcher.matches(
+            pmock.Invocation("snake", ("slither", "hiss"), {})))
+
+    def test_extra_keyword_arguments(self):
+        args_matcher = pmock.AllArgumentsMatcher((),
+                                                 {"food": pmock.eq("goat")})
+        self.assert_(not args_matcher.matches(
+            pmock.Invocation("snake", (), {"food": "goat", "colour": "red"})))
+
+    def test_no_arguments(self):
+        args_matcher = pmock.AllArgumentsMatcher()
+        self.assert_(args_matcher.matches(pmock.Invocation("snake", (), {})))
+        self.assert_(
+            not args_matcher.matches(pmock.Invocation("snake", ("hiss",), {})))
+        self.assert_(not args_matcher.matches(
+            pmock.Invocation("snake", (), {"food": "goat"})))
+
+    def test_str(self):
+        matcher = pmock.AllArgumentsMatcher((pmock.eq("slither"),),
+                                            {"food": pmock.eq("goat")})
+        self.assertEqual(str(matcher),
+                         "(pmock.eq('slither'), food=pmock.eq('goat'))")
+
+    def test_empty_str(self):
+        self.assertEqual(str(pmock.AllArgumentsMatcher()), "()")
+
+
+class LeastArgumentsMatcherTest(ArgumentsMatcherTestMixin, unittest.TestCase):
+
+    def __init__(self, *args):
+        ArgumentsMatcherTestMixin.__init__(self, pmock.LeastArgumentsMatcher)
+        unittest.TestCase.__init__(self, *args)        
+    
+    def test_extra_arguments(self):
+        args_matcher = pmock.LeastArgumentsMatcher((pmock.eq("slither"),), {})
+        self.assert_(args_matcher.matches(
+            pmock.Invocation("snake", ("slither", "hiss"), {})))
+
+    def test_extra_keyword_arguments(self):
+        args_matcher = pmock.LeastArgumentsMatcher((),
+                                                 {"food": pmock.eq("goat")})
+        self.assert_(args_matcher.matches(
+            pmock.Invocation("snake", (), {"food": "goat", "colour": "red"})))
+
+    def test_any_arguments(self):
+        args_matcher = pmock.LeastArgumentsMatcher()
+        self.assert_(args_matcher.matches(pmock.Invocation("snake", (), {})))
+        self.assert_(
+            args_matcher.matches(pmock.Invocation("snake", ("hiss",), {})))
+        self.assert_(args_matcher.matches(
+            pmock.Invocation("snake", ("constrict",), {"food": "goat"})))
+
+    def test_str(self):
+        matcher = pmock.LeastArgumentsMatcher((pmock.eq("slither"),),
+                                              {"food": pmock.eq("goat")})
+        self.assertEqual(str(matcher),
+                         "(pmock.eq('slither'), food=pmock.eq('goat'), ...)")
+
+    def test_empty_str(self):
+        self.assertEqual(str(pmock.LeastArgumentsMatcher()), "(...)")
+
+
+class InvocationMockerTest(unittest.TestCase):
+
+    class MockMatcher:
+        def __init__(self, matches):
+            self._matches = matches
+        def matches(self, invocation):
+            self.matches_invocation = invocation
+            return self._matches
+        def invoked(self, invocation):
+            self.invoked_invocation = invocation
+    
+    def test_matches(self):
+        mocker = pmock.InvocationMocker(self.MockMatcher(True))
+        self.assert_(mocker.matches(pmock.Invocation("duck", (), {})))
+
+    def test_unmatched(self):
+        mocker = pmock.InvocationMocker(self.MockMatcher(False))
+        self.assert_(not mocker.matches(pmock.Invocation("duck", (), {})))
+
+    def test_added_matcher_unmatched(self):
+        mocker = pmock.InvocationMocker(self.MockMatcher(True))
+        mocker.add_matcher(self.MockMatcher(False))
+        self.assert_(not mocker.matches(pmock.Invocation("duck", (), {})))
+
+    def test_matches_passes_invocation_to_matcher(self):
+        matcher = self.MockMatcher(True)
+        mocker = pmock.InvocationMocker(matcher)
+        invocation = pmock.Invocation("duck", (), {})
+        mocker.matches(invocation)
+        self.assertEqual(matcher.matches_invocation, invocation)
+
+    def test_no_stub_returns_none(self):
+        mocker = pmock.InvocationMocker(self.MockMatcher(True))
+        self.assert_(mocker.invoke(pmock.Invocation("duck", (), {})) is None)
+
+    def test_invoke_returns_stubs_value(self):
+        class MockStub:
+            def invoke(self, invocation): return 'value'
+        mocker = pmock.InvocationMocker(self.MockMatcher(True))
+        mocker.set_stub(MockStub())
+        self.assert_(mocker.invoke(pmock.Invocation("duck", (), {})) ==
+                     'value')
+
+    def test_invoke_passes_invocation_to_matcher(self):
+        matcher1 = self.MockMatcher(True)
+        matcher2 = self.MockMatcher(True)
+        mocker = pmock.InvocationMocker(matcher1)
+        mocker.add_matcher(matcher2)
+        invocation = pmock.Invocation("duck", (), {})
+        mocker.invoke(invocation)
+        self.assertEqual(matcher1.invoked_invocation, invocation)
+        self.assertEqual(matcher2.invoked_invocation, invocation)
+
+    def test_verify(self):
+        class MockInvocationMatcher:
+            def __init__(self, raises, str_str):
+                self.raises = raises
+                self.str_str = str_str
+                self.verified = False
+            def __str__(self):
+                return self.str_str
+            def verify(self):
+                self.verified = True
+                if self.raises:
+                    raise AssertionError("problem")
+        matcher1 = MockInvocationMatcher(False, "one")
+        matcher2 = MockInvocationMatcher(True, "two")
+        matcher3 = MockInvocationMatcher(True, "three")
+        mocker = pmock.InvocationMocker(matcher1)
+        mocker.add_matcher(matcher2)
+        mocker.add_matcher(matcher3)
+        try:
+            mocker.verify()
+            self.fail("expected verify to raise")
+        except pmock.VerificationError, err:
+            self.assert_(matcher1.verified)
+            self.assert_(matcher2.verified)
+            self.assert_(not matcher3.verified)
+            self.assertEqual(err.msg, "problem: %s" % mocker)
+            
+    def test_str(self):
+        class MockMatcher:
+            def __init__(self, str_str): self._str = str_str
+            def __str__(self): return self._str
+        MockStub = MockMatcher
+        mocker = pmock.InvocationMocker(MockMatcher("invocation_matcher"))
+        mocker.add_matcher(MockMatcher("added_matcher1"))
+        mocker.add_matcher(MockMatcher("added_matcher2"))
+        mocker.set_stub(MockStub("stub"))
+        self.assertEqual(str(mocker),
+                         "invocation_matcher: added_matcher1added_matcher2, "
+                         "stub")
+
+    def test_no_id_str(self):
+        class MockMatcher:
+            def __init__(self, str_str): self._str = str_str
+            def __str__(self): return self._str
+        mocker = pmock.InvocationMocker(MockMatcher("invocation_matcher"))
+        mocker.add_matcher(MockMatcher("added_matcher1"))
+        self.assertEqual(str(mocker), "invocation_matcher: added_matcher1")
+
+    def test_id_str(self):
+        class MockMatcher:
+            def __init__(self, str_str): self._str = str_str
+            def __str__(self): return self._str
+        MockStub = MockMatcher
+        mocker = pmock.InvocationMocker(MockMatcher("invocation_matcher"))
+        mocker.add_matcher(MockMatcher("added_matcher1"))
+        mocker.set_stub(MockStub("stub"))
+        mocker.set_id("quack")
+        self.assertEqual(str(mocker),
+                         "invocation_matcher: added_matcher1, stub [quack]")
+
+
+class InvocationMockerBuilderTest(testsupport.ErrorMsgAssertsMixin,
+                                  unittest.TestCase):
+
+    class MockInvocationMocker:
+        def __init__(self):
+            self.added_matchers = []
+            self.id = None
+            self.stub = None
+        def add_matcher(self, matcher):
+            self.added_matchers.append(matcher)
+        def set_id(self, mocker_id):
+            self.id = mocker_id
+        def set_stub(self, stub):
+            self.stub = stub
+        def _get_only_added_matcher(self):
+            if len(self.added_matchers) != 1:
+                raise AssertionError('more than one matcher has been added')
+            return self.added_matchers[0]
+        added_matcher = property(_get_only_added_matcher)
+
+    def setUp(self):
+        self.mocker = self.MockInvocationMocker()
+        self.builder_namespace = pmock.Mock()
+        self.builder = pmock.InvocationMockerBuilder(self.mocker,
+                                                     self.builder_namespace)
+
+    def test_add_method_matcher(self):
+        self.assert_(self.builder.method("chicken") is not None)
+        self.assert_(isinstance(self.mocker.added_matcher,
+                                pmock.MethodMatcher))
+        self.assert_(self.mocker.added_matcher.matches(
+            pmock.Invocation("chicken", (), {})))
+        self.assertEqual(self.builder_namespace.lookup_id("chicken"),
+                         self.builder)
+
+    def test_add_direct_method_matcher(self):
+        self.assert_(self.builder.chicken() is not None)
+        self.assert_(isinstance(self.mocker.added_matchers[0],
+                                pmock.MethodMatcher))
+        self.assert_(self.mocker.added_matchers[0].matches(
+            pmock.Invocation("chicken", (), {})))
+        self.assert_(self.mocker.added_matchers[1].matches(
+            pmock.Invocation("chicken", (), {})))
+        self.assertEqual(self.builder_namespace.lookup_id("chicken"),
+                         self.builder)
+
+    def test_add_direct_method_and_arg_matcher(self):
+        self.assert_(self.builder.chicken(pmock.eq("egg")) is not None)
+        self.assert_(isinstance(self.mocker.added_matchers[0],
+                                pmock.MethodMatcher))
+        self.assert_(self.mocker.added_matchers[0].matches(
+            pmock.Invocation("chicken", (), {})))
+        self.assert_(self.mocker.added_matchers[1].matches(
+            pmock.Invocation("chicken", ("egg",), {})))
+        self.assertEqual(self.builder_namespace.lookup_id("chicken"),
+                         self.builder)
+
+    def test_add_with_matcher(self):
+        self.assert_(self.builder.with(pmock.eq("egg")) is not None)
+        self.assert_(isinstance(self.mocker.added_matcher,
+                                pmock.AllArgumentsMatcher))
+        self.assert_(self.mocker.added_matcher.matches(
+            pmock.Invocation(None, ("egg",), {})))
+
+    def test_add_with_at_least_matcher(self):
+        self.assert_(self.builder.with_at_least(pmock.eq("egg")) is not None)
+        self.assert_(isinstance(self.mocker.added_matcher,
+                                pmock.LeastArgumentsMatcher))
+        self.assert_(self.mocker.added_matcher.matches(
+            pmock.Invocation(None, ("egg", "feather"), {})))
+
+    def test_add_no_args_matcher(self):
+        self.assert_(self.builder.no_args() is not None)
+        self.assertEqual(self.mocker.added_matcher, pmock.NO_ARGS_MATCHER)
+
+    def test_add_any_args_matcher(self):
+        self.assert_(self.builder.any_args() is not None)
+        self.assertEqual(self.mocker.added_matcher, pmock.ANY_ARGS_MATCHER)
+
+    def test_set_will_stub(self):
+        class MockStub: pass
+        stub = MockStub()
+        self.assert_(self.builder.will(stub) is not None)
+        self.assertEqual(self.mocker.stub, stub)
+
+    def test_set_id(self):
+        self.assert_(self.builder.id("poultry") is not None)
+        self.assertEqual(self.mocker.id, "poultry")
+        self.assertEqual(self.builder_namespace.lookup_id("poultry"),
+                         self.builder)
+
+    def test_set_duplicate_id(self):
+        self.builder.id("poultry")
+        try:
+            self.builder.id("poultry")
+            self.fail("mocker with duplicate ids should raise")
+        except pmock.DefinitionError, err:
+            self.assertDuplicateIdMsg(err.msg, "poultry")