diff options
author | smiddlek <smiddlek@b1010a0a-674b-0410-b734-77272b80c875> | 2010-03-18 17:04:35 +0000 |
---|---|---|
committer | smiddlek <smiddlek@b1010a0a-674b-0410-b734-77272b80c875> | 2010-03-18 17:04:35 +0000 |
commit | 33f2e36889a478ee5c26a56625f8505c72a9772d (patch) | |
tree | 7a7de76107fe914cfd47ac667d8ff4ce9608fed6 | |
parent | 8d018291d83381d57fe40305ee504861d44f8bcc (diff) | |
download | mox-33f2e36889a478ee5c26a56625f8505c72a9772d.tar.gz |
Thanks to matthew.blain@google.com for ContainsAttributeValue comparator
and Adeodato Simo for adding stubs to the MoxTestBase and fixing up some
of the tests.
git-svn-id: http://pymox.googlecode.com/svn/trunk@40 b1010a0a-674b-0410-b734-77272b80c875
-rwxr-xr-x | mox.py | 64 | ||||
-rwxr-xr-x | mox_test.py | 153 | ||||
-rwxr-xr-x | mox_test_helper.py | 19 |
3 files changed, 220 insertions, 16 deletions
@@ -430,6 +430,16 @@ class MockObject(MockAnything, object): self._known_methods = set() self._known_vars = set() self._class_to_mock = class_to_mock + try: + self._description = class_to_mock.__name__ + # If class_to_mock is a mock itself, then we'll get an UnknownMethodCall + # error here from the underlying call to __getattr__('__name__') + except (UnknownMethodCallError, AttributeError): + try: + self._description = type(class_to_mock).__name__ + except AttributeError: + pass + for method in dir(class_to_mock): if callable(getattr(class_to_mock, method)): self._known_methods.add(method) @@ -761,6 +771,7 @@ class MockMethod(object): """ self._name = method_name + self.__name__ = method_name self._call_queue = call_queue if not isinstance(call_queue, deque): self._call_queue = deque(self._call_queue) @@ -803,7 +814,9 @@ class MockMethod(object): expected_method = self._VerifyMethodCall() if expected_method._side_effects: - expected_method._side_effects(*params, **named_params) + result = expected_method._side_effects(*params, **named_params) + if expected_method._return_value is None: + expected_method._return_value = result if expected_method._exception: raise expected_method._exception @@ -1286,6 +1299,37 @@ class ContainsKeyValue(Comparator): return '<map containing the entry \'%s: %s\'>' % (self._key, self._value) +class ContainsAttributeValue(Comparator): + """Checks whether a passed parameter contains attributes with a given value. + + Example: + mock_dao.UpdateSomething(ContainsAttribute('stevepm', stevepm_user_info)) + """ + + def __init__(self, key, value): + """Initialize. + + Args: + # key: an attribute name of an object + # value: the corresponding value + """ + + self._key = key + self._value = value + + def equals(self, rhs): + """Check whether the given attribute has a matching value in the rhs object. + + Returns: + bool + """ + + try: + return getattr(rhs, self._key) == self._value + except Exception: + return False + + class SameElementsAs(Comparator): """Checks whether iterables contain the same elements (ignoring order). @@ -1621,7 +1665,8 @@ class MoxMetaTestBase(type): # for a case when test class is not the immediate child of MoxTestBase for base in bases: for attr_name in dir(base): - d[attr_name] = getattr(base, attr_name) + if attr_name not in d: + d[attr_name] = getattr(base, attr_name) for func_name, func in d.items(): if func_name.startswith('test') and callable(func): @@ -1643,14 +1688,21 @@ class MoxMetaTestBase(type): """ def new_method(self, *args, **kwargs): mox_obj = getattr(self, 'mox', None) + stubout_obj = getattr(self, 'stubs', None) cleanup_mox = False + cleanup_stubout = False if mox_obj and isinstance(mox_obj, Mox): cleanup_mox = True + if stubout_obj and isinstance(stubout_obj, stubout.StubOutForTesting): + cleanup_stubout = True try: func(self, *args, **kwargs) finally: if cleanup_mox: mox_obj.UnsetStubs() + if cleanup_stubout: + stubout_obj.UnsetAll() + stubout_obj.SmartUnsetAll() if cleanup_mox: mox_obj.VerifyAll() new_method.__name__ = func.__name__ @@ -1662,9 +1714,10 @@ class MoxMetaTestBase(type): class MoxTestBase(unittest.TestCase): """Convenience test class to make stubbing easier. - Sets up a "mox" attribute which is an instance of Mox - any mox tests will - want this. Also automatically unsets any stubs and verifies that all mock - methods have been called at the end of each test, eliminating boilerplate + Sets up a "mox" attribute which is an instance of Mox (any mox tests will + want this), and a "stubs" attribute that is an instance of StubOutForTesting + (needed at times). Also automatically unsets any stubs and verifies that all + mock methods have been called at the end of each test, eliminating boilerplate code. """ @@ -1673,3 +1726,4 @@ class MoxTestBase(unittest.TestCase): def setUp(self): super(MoxTestBase, self).setUp() self.mox = Mox() + self.stubs = stubout.StubOutForTesting() diff --git a/mox_test.py b/mox_test.py index e1626d6..ea12176 100755 --- a/mox_test.py +++ b/mox_test.py @@ -24,6 +24,7 @@ import mox import mox_test_helper +OS_LISTDIR = mox_test_helper.os.listdir class ExpectedMethodCallsErrorTest(unittest.TestCase): """Test creation and string conversion of ExpectedMethodCallsError.""" @@ -147,6 +148,32 @@ class ContainsKeyValueTest(unittest.TestCase): self.failIf(mox.ContainsKeyValue("qux", 1) == {"key": 2}) +class ContainsAttributeValueTest(unittest.TestCase): + """Test ContainsAttributeValue correctly identifies properties in an object. + """ + + def setUp(self): + """Create an object to test with.""" + + + class TestObject(object): + key = 1 + + self.test_object = TestObject() + + def testValidPair(self): + """Should return True if the object has the key attribute and it matches.""" + self.assert_(mox.ContainsAttributeValue("key", 1) == self.test_object) + + def testInvalidValue(self): + """Should return False if the value is not correct.""" + self.failIf(mox.ContainsKeyValue("key", 2) == self.test_object) + + def testInvalidKey(self): + """Should return False if they the object doesn't have the property.""" + self.failIf(mox.ContainsKeyValue("qux", 1) == self.test_object) + + class InTest(unittest.TestCase): """Test In correctly identifies a key in a list/dict""" @@ -302,6 +329,10 @@ class MockMethodTest(unittest.TestCase): self.mock_method = mox.MockMethod("testMethod", [self.expected_method], True) + def testNameAttribute(self): + """Should provide a __name__ attribute.""" + self.assertEquals('testMethod', self.mock_method.__name__) + def testAndReturnNoneByDefault(self): """Should return None by default.""" return_value = self.mock_method(['original']) @@ -330,6 +361,34 @@ class MockMethodTest(unittest.TestCase): self.mock_method(local_list) self.assertEquals('mutation', local_list[0]) + def testWithReturningSideEffects(self): + """Should call state modifier and propagate its return value.""" + local_list = ['original'] + expected_return = 'expected_return' + def modifier_with_return(mutable_list): + self.assertTrue(local_list is mutable_list) + mutable_list[0] = 'mutation' + return expected_return + self.expected_method.WithSideEffects(modifier_with_return) + actual_return = self.mock_method(local_list) + self.assertEquals('mutation', local_list[0]) + self.assertEquals(expected_return, actual_return) + + def testWithReturningSideEffectsWithAndReturn(self): + """Should call state modifier and ignore its return value.""" + local_list = ['original'] + expected_return = 'expected_return' + unexpected_return = 'unexpected_return' + def modifier_with_return(mutable_list): + self.assertTrue(local_list is mutable_list) + mutable_list[0] = 'mutation' + return unexpected_return + self.expected_method.WithSideEffects(modifier_with_return).AndReturn( + expected_return) + actual_return = self.mock_method(local_list) + self.assertEquals('mutation', local_list[0]) + self.assertEquals(expected_return, actual_return) + def testEqualityNoParamsEqual(self): """Methods with the same name and without params should be equal.""" expected_method = mox.MockMethod("testMethod", [], False) @@ -931,6 +990,7 @@ class MockObjectTest(unittest.TestCase): self.assertEqual([x for x in dummy], ['X', 'Y']) dummy._Verify() + def testMockContains_ExpectedContains_Success(self): """Test that __contains__ gets mocked in Dummy. @@ -1421,6 +1481,26 @@ class MoxTest(unittest.TestCase): self.assertEquals('foo', actual) self.failIf(isinstance(test_obj.OtherValidCall, mox.MockAnything)) + def testStubOutClass(self): + """Test a mocked class whose __init__ returns a Mock.""" + self.mox.StubOutWithMock(mox_test_helper, 'TestClassFromAnotherModule') + self.assert_(isinstance(mox_test_helper.TestClassFromAnotherModule, + mox.MockObject)) + + mock_instance = self.mox.CreateMock( + mox_test_helper.TestClassFromAnotherModule) + mox_test_helper.TestClassFromAnotherModule().AndReturn(mock_instance) + mock_instance.Value().AndReturn('mock instance') + + self.mox.ReplayAll() + + a_mock = mox_test_helper.TestClassFromAnotherModule() + actual = a_mock.Value() + + self.mox.VerifyAll() + self.mox.UnsetStubs() + self.assertEquals('mock instance', actual) + def testWarnsUserIfMockingMock(self): """Test that user is warned if they try to stub out a MockAnything.""" self.mox.StubOutWithMock(TestClass, 'MyStaticMethod') @@ -1478,12 +1558,14 @@ class MoxTestBaseTest(unittest.TestCase): def setUp(self): self.mox = mox.Mox() self.test_mox = mox.Mox() + self.test_stubs = mox.stubout.StubOutForTesting() self.result = unittest.TestResult() def tearDown(self): - # In case one of our tests fail before UnsetStubs is called. self.mox.UnsetStubs() self.test_mox.UnsetStubs() + self.test_stubs.UnsetAll() + self.test_stubs.SmartUnsetAll() def _setUpTestClass(self): """Replacement for setUp in the test class instance. @@ -1493,6 +1575,7 @@ class MoxTestBaseTest(unittest.TestCase): in the test class instance. """ self.test.mox = self.test_mox + self.test.stubs = self.test_stubs def _CreateTest(self, test_name): """Create a test from our example mox class. @@ -1506,14 +1589,17 @@ class MoxTestBaseTest(unittest.TestCase): """Run the checks to confirm test method completed successfully.""" self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') self.mox.StubOutWithMock(self.test_mox, 'VerifyAll') + self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') + self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') self.test_mox.UnsetStubs() self.test_mox.VerifyAll() + self.test_stubs.UnsetAll() + self.test_stubs.SmartUnsetAll() self.mox.ReplayAll() self.test.run(result=self.result) self.assertTrue(self.result.wasSuccessful()) - self.mox.UnsetStubs() self.mox.VerifyAll() - self.test_mox.UnsetStubs() + self.mox.UnsetStubs() # Needed to call the real VerifyAll() below. self.test_mox.VerifyAll() def testSuccess(self): @@ -1521,47 +1607,78 @@ class MoxTestBaseTest(unittest.TestCase): self._CreateTest('testSuccess') self._VerifySuccess() + def testSuccessNoMocks(self): + """Let testSuccess() unset all the mocks, and verify they've been unset.""" + self._CreateTest('testSuccess') + self.test.run(result=self.result) + self.assertTrue(self.result.wasSuccessful()) + self.assertEqual(OS_LISTDIR, mox_test_helper.os.listdir) + + def testStubs(self): + """Test that "self.stubs" is provided as is useful.""" + self._CreateTest('testHasStubs') + self._VerifySuccess() + + def testStubsNoMocks(self): + """Let testHasStubs() unset the stubs by itself.""" + self._CreateTest('testHasStubs') + self.test.run(result=self.result) + self.assertTrue(self.result.wasSuccessful()) + self.assertEqual(OS_LISTDIR, mox_test_helper.os.listdir) + def testExpectedNotCalled(self): """Stubbed out method is not called.""" self._CreateTest('testExpectedNotCalled') self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') - # Dont stub out VerifyAll - that's what causes the test to fail + self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') + self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') + # Don't stub out VerifyAll - that's what causes the test to fail self.test_mox.UnsetStubs() - self.test_mox.VerifyAll() + self.test_stubs.UnsetAll() + self.test_stubs.SmartUnsetAll() self.mox.ReplayAll() self.test.run(result=self.result) self.failIf(self.result.wasSuccessful()) - self.mox.UnsetStubs() self.mox.VerifyAll() - self.test_mox.UnsetStubs() + + def testExpectedNotCalledNoMocks(self): + """Let testExpectedNotCalled() unset all the mocks by itself.""" + self._CreateTest('testExpectedNotCalled') + self.test.run(result=self.result) + self.failIf(self.result.wasSuccessful()) + self.assertEqual(OS_LISTDIR, mox_test_helper.os.listdir) def testUnexpectedCall(self): """Stubbed out method is called with unexpected arguments.""" self._CreateTest('testUnexpectedCall') self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') + self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') + self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') # Ensure no calls are made to VerifyAll() self.mox.StubOutWithMock(self.test_mox, 'VerifyAll') self.test_mox.UnsetStubs() + self.test_stubs.UnsetAll() + self.test_stubs.SmartUnsetAll() self.mox.ReplayAll() self.test.run(result=self.result) self.failIf(self.result.wasSuccessful()) - self.mox.UnsetStubs() self.mox.VerifyAll() - self.test_mox.UnsetStubs() def testFailure(self): """Failing assertion in test method.""" self._CreateTest('testFailure') self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') + self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') + self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') # Ensure no calls are made to VerifyAll() self.mox.StubOutWithMock(self.test_mox, 'VerifyAll') self.test_mox.UnsetStubs() + self.test_stubs.UnsetAll() + self.test_stubs.SmartUnsetAll() self.mox.ReplayAll() self.test.run(result=self.result) self.failIf(self.result.wasSuccessful()) - self.mox.UnsetStubs() self.mox.VerifyAll() - self.test_mox.UnsetStubs() def testMixin(self): """Run test from mix-in test class, ensure it passes.""" @@ -1615,6 +1732,12 @@ class MyTestCase(unittest.TestCase): def setUp(self): super(MyTestCase, self).setUp() self.critical_variable = 42 + self.another_critical_variable = 42 + + def testMethodOverride(self): + """Should be properly overriden in a derived class.""" + self.assertEquals(42, self.another_critical_variable) + self.another_critical_variable += 1 class MoxTestBaseMultipleInheritanceTest(mox.MoxTestBase, MyTestCase): @@ -1622,12 +1745,20 @@ class MoxTestBaseMultipleInheritanceTest(mox.MoxTestBase, MyTestCase): def setUp(self): super(MoxTestBaseMultipleInheritanceTest, self).setUp() + self.another_critical_variable = 99 def testMultipleInheritance(self): """Should be able to access members created by all parent setUp().""" self.assert_(isinstance(self.mox, mox.Mox)) self.assertEquals(42, self.critical_variable) + def testMethodOverride(self): + """Should run before MyTestCase.testMethodOverride.""" + self.assertEquals(99, self.another_critical_variable) + self.another_critical_variable = 42 + super(MoxTestBaseMultipleInheritanceTest, self).testMethodOverride() + self.assertEquals(43, self.another_critical_variable) + class TestClass: """This class is used only for testing the mock framework""" diff --git a/mox_test_helper.py b/mox_test_helper.py index 164c0ec..b4bfdec 100755 --- a/mox_test_helper.py +++ b/mox_test_helper.py @@ -74,3 +74,22 @@ class ExampleMoxTest(mox.MoxTestBase, ExampleMoxTestMixin): os.stat(self.DIR_PATH) self.mox.ReplayAll() os.stat(self.DIR_PATH) + + def testHasStubs(self): + listdir_list = [] + + def MockListdir(directory): + listdir_list.append(directory) + + self.stubs.Set(os, 'listdir', MockListdir) + os.listdir(self.DIR_PATH) + self.assertEqual([self.DIR_PATH], listdir_list) + + +class TestClassFromAnotherModule(object): + + def __init__(): + return None + + def Value(): + return "Not mock" |