summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustavo Niemeyer <gustavo@niemeyer.net>2007-11-17 15:30:34 -0200
committerGustavo Niemeyer <gustavo@niemeyer.net>2007-11-17 15:30:34 -0200
commit745fc9a11340f192e2f73c0f1f3101866d26f74f (patch)
tree2626e5ddf71d2d96e6d358b7f0e55c5d2d713e9e
parent90e0d73ee9238af7c80d9342a028d04028d4ae3a (diff)
downloadmocker-745fc9a11340f192e2f73c0f1f3101866d26f74f.tar.gz
Added MockerTestCase.assertMethodsMatch(). It will verify if all
public methods found in the class passed as the first argument are also present in the class passed as the second argument, and that they accept the same arguments. This is useful to verify if a fake or stub class have the same API as the real class being simulated.
-rw-r--r--NEWS6
-rw-r--r--mocker.py34
-rwxr-xr-xtest.py62
3 files changed, 102 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 9ff0dbc..8d43cb5 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,12 @@
easy creation of temporary files/directories, and ensure that they
get removed after each test method runs.
+- Added MockerTestCase.assertMethodsMatch(). It will verify if all
+ public methods found in the class passed as the first argument are
+ also present in the class passed as the second argument, and that
+ they accept the same arguments. This is useful to verify if a fake
+ or stub class have the same API as the real class being simulated.
+
- If the replay() method is called twice, expectations will be fully
reset so that several similar tests may be performed in a row by
just calling replay() again.
diff --git a/mocker.py b/mocker.py
index fe27892..7d7160c 100644
--- a/mocker.py
+++ b/mocker.py
@@ -192,12 +192,46 @@ class MockerTestCase(unittest.TestCase):
raise self.failureException(msg or "abs(%r - %r) <= %r" %
(first, second, tolerance))
+ def failUnlessMethodsMatch(self, first, second):
+ """Assert that public methods in C{first} are present in C{second}.
+
+ This method asserts that all public methods found in C{first} are also
+ present in C{second} and accept the same arguments. C{first} may
+ have its own private methods, though, and may not have all methods
+ found in C{second}. Note that if a private method in C{first} matches
+ the name of one in C{second}, their specification is still compared.
+
+ This is useful to verify if a fake or stub class have the same API as
+ the real class being simulated.
+ """
+ first_methods = dict(inspect.getmembers(first, inspect.ismethod))
+ second_methods = dict(inspect.getmembers(second, inspect.ismethod))
+ for name, first_method in first_methods.items():
+ first_argspec = inspect.getargspec(first_method)
+ first_formatted = inspect.formatargspec(*first_argspec)
+
+ second_method = second_methods.get(name)
+ if second_method is None:
+ if name[:1] == "_":
+ continue # First may have its own private methods.
+ raise self.failureException("%s.%s%s not present in %s" %
+ (first.__name__, name, first_formatted, second.__name__))
+
+ second_argspec = inspect.getargspec(second_method)
+ if first_argspec != second_argspec:
+ second_formatted = inspect.formatargspec(*second_argspec)
+ raise self.failureException("%s.%s%s != %s.%s%s" %
+ (first.__name__, name, first_formatted,
+ second.__name__, name, second_formatted))
+
+
assertIs = failUnlessIs
assertIsNot = failIfIs
assertIn = failUnlessIn
assertNotIn = failIfIn
assertApproximates = failUnlessApproximates
assertNotApproximates = failIfApproximates
+ assertMethodsMatch = failUnlessMethodsMatch
# The following is provided for compatibility with Twisted's trial.
assertIdentical = assertIs
diff --git a/test.py b/test.py
index 1d8acc6..62c1230 100755
--- a/test.py
+++ b/test.py
@@ -481,6 +481,65 @@ class MockerTestCaseTest(unittest.TestCase):
except AssertionError:
self.fail("AssertionError shouldn't be raised")
+ def test_fail_unless_methods_match_raises_on_different_method(self):
+ class Fake(object):
+ def method(self, a): pass
+ class Real(object):
+ def method(self, b): pass
+ try:
+ self.test.failUnlessMethodsMatch(Fake, Real)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Fake.method(self, a) != "
+ "Real.method(self, b)")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_methods_match_raises_on_missing_method(self):
+ class Fake(object):
+ def method(self, a): pass
+ class Real(object):
+ pass
+ try:
+ self.test.failUnlessMethodsMatch(Fake, Real)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Fake.method(self, a) not present "
+ "in Real")
+ else: self.fail("AssertionError not raised")
+
+ def test_fail_unless_methods_match_succeeds_on_missing_priv_method(self):
+ class Fake(object):
+ def _method(self, a): pass
+ class Real(object):
+ pass
+ try:
+ self.test.failUnlessMethodsMatch(Fake, Real)
+ except AssertionError, e:
+ self.fail("AssertionError shouldn't be raised")
+
+ def test_fail_unless_methods_match_raises_on_different_priv_method(self):
+ class Fake(object):
+ def _method(self, a): pass
+ class Real(object):
+ def _method(self, b): pass
+ try:
+ self.test.failUnlessMethodsMatch(Fake, Real)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Fake._method(self, a) != "
+ "Real._method(self, b)")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_methods_match_succeeds(self):
+ class Fake(object):
+ def method(self, a): pass
+ class Real(object):
+ def method(self, a): pass
+ obj = []
+ try:
+ self.test.failUnlessMethodsMatch(Fake, Real)
+ except AssertionError:
+ self.fail("AssertionError shouldn't be raised")
+
def test_aliases(self):
get_method = MockerTestCase.__dict__.get
@@ -502,6 +561,9 @@ class MockerTestCaseTest(unittest.TestCase):
self.assertEquals(get_method("assertNotApproximates"),
get_method("failIfApproximates"))
+ self.assertEquals(get_method("assertMethodsMatch"),
+ get_method("failUnlessMethodsMatch"))
+
def test_twisted_trial_aliases(self):
get_method = MockerTestCase.__dict__.get