diff options
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | mocker.py | 34 | ||||
-rwxr-xr-x | test.py | 62 |
3 files changed, 102 insertions, 0 deletions
@@ -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. @@ -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 @@ -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 |