summaryrefslogtreecommitdiff
path: root/mox_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'mox_test.py')
-rwxr-xr-xmox_test.py1326
1 files changed, 1326 insertions, 0 deletions
diff --git a/mox_test.py b/mox_test.py
new file mode 100755
index 0000000..df83c45
--- /dev/null
+++ b/mox_test.py
@@ -0,0 +1,1326 @@
+#!/usr/bin/python2.4
+#
+# Unit tests for Mox.
+#
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import cStringIO
+import unittest
+import re
+
+import mox
+
+import mox_test_helper
+
+
+class ExpectedMethodCallsErrorTest(unittest.TestCase):
+ """Test creation and string conversion of ExpectedMethodCallsError."""
+
+ def testAtLeastOneMethod(self):
+ self.assertRaises(ValueError, mox.ExpectedMethodCallsError, [])
+
+ def testOneError(self):
+ method = mox.MockMethod("testMethod", [], False)
+ method(1, 2).AndReturn('output')
+ e = mox.ExpectedMethodCallsError([method])
+ self.assertEqual(
+ "Verify: Expected methods never called:\n"
+ " 0. testMethod(1, 2) -> 'output'",
+ str(e))
+
+ def testManyErrors(self):
+ method1 = mox.MockMethod("testMethod", [], False)
+ method1(1, 2).AndReturn('output')
+ method2 = mox.MockMethod("testMethod", [], False)
+ method2(a=1, b=2, c="only named")
+ method3 = mox.MockMethod("testMethod2", [], False)
+ method3().AndReturn(44)
+ method4 = mox.MockMethod("testMethod", [], False)
+ method4(1, 2).AndReturn('output')
+ e = mox.ExpectedMethodCallsError([method1, method2, method3, method4])
+ self.assertEqual(
+ "Verify: Expected methods never called:\n"
+ " 0. testMethod(1, 2) -> 'output'\n"
+ " 1. testMethod(a=1, b=2, c='only named') -> None\n"
+ " 2. testMethod2() -> 44\n"
+ " 3. testMethod(1, 2) -> 'output'",
+ str(e))
+
+
+class OrTest(unittest.TestCase):
+ """Test Or correctly chains Comparators."""
+
+ def testValidOr(self):
+ """Or should be True if either Comparator returns True."""
+ self.assert_(mox.Or(mox.IsA(dict), mox.IsA(str)) == {})
+ self.assert_(mox.Or(mox.IsA(dict), mox.IsA(str)) == 'test')
+ self.assert_(mox.Or(mox.IsA(str), mox.IsA(str)) == 'test')
+
+ def testInvalidOr(self):
+ """Or should be False if both Comparators return False."""
+ self.failIf(mox.Or(mox.IsA(dict), mox.IsA(str)) == 0)
+
+
+class AndTest(unittest.TestCase):
+ """Test And correctly chains Comparators."""
+
+ def testValidAnd(self):
+ """And should be True if both Comparators return True."""
+ self.assert_(mox.And(mox.IsA(str), mox.IsA(str)) == '1')
+
+ def testClauseOneFails(self):
+ """And should be False if the first Comparator returns False."""
+
+ self.failIf(mox.And(mox.IsA(dict), mox.IsA(str)) == '1')
+
+ def testAdvancedUsage(self):
+ """And should work with other Comparators.
+
+ Note: this test is reliant on In and ContainsKeyValue.
+ """
+ test_dict = {"mock" : "obj", "testing" : "isCOOL"}
+ self.assert_(mox.And(mox.In("testing"),
+ mox.ContainsKeyValue("mock", "obj")) == test_dict)
+
+ def testAdvancedUsageFails(self):
+ """Note: this test is reliant on In and ContainsKeyValue."""
+ test_dict = {"mock" : "obj", "testing" : "isCOOL"}
+ self.failIf(mox.And(mox.In("NOTFOUND"),
+ mox.ContainsKeyValue("mock", "obj")) == test_dict)
+
+
+class SameElementsAsTest(unittest.TestCase):
+ """Test SameElementsAs correctly identifies sequences with same elements."""
+
+ def testSortedLists(self):
+ """Should return True if two lists are exactly equal."""
+ self.assert_(mox.SameElementsAs([1, 2.0, 'c']) == [1, 2.0, 'c'])
+
+ def testUnsortedLists(self):
+ """Should return True if two lists are unequal but have same elements."""
+ self.assert_(mox.SameElementsAs([1, 2.0, 'c']) == [2.0, 'c', 1])
+
+ def testUnhashableLists(self):
+ """Should return True if two lists have the same unhashable elements."""
+ self.assert_(mox.SameElementsAs([{'a': 1}, {2: 'b'}]) ==
+ [{2: 'b'}, {'a': 1}])
+
+ def testEmptyLists(self):
+ """Should return True for two empty lists."""
+ self.assert_(mox.SameElementsAs([]) == [])
+
+ def testUnequalLists(self):
+ """Should return False if the lists are not equal."""
+ self.failIf(mox.SameElementsAs([1, 2.0, 'c']) == [2.0, 'c'])
+
+ def testUnequalUnhashableLists(self):
+ """Should return False if two lists with unhashable elements are unequal."""
+ self.failIf(mox.SameElementsAs([{'a': 1}, {2: 'b'}]) == [{2: 'b'}])
+
+
+class ContainsKeyValueTest(unittest.TestCase):
+ """Test ContainsKeyValue correctly identifies key/value pairs in a dict.
+ """
+
+ def testValidPair(self):
+ """Should return True if the key value is in the dict."""
+ self.assert_(mox.ContainsKeyValue("key", 1) == {"key": 1})
+
+ def testInvalidValue(self):
+ """Should return False if the value is not correct."""
+ self.failIf(mox.ContainsKeyValue("key", 1) == {"key": 2})
+
+ def testInvalidKey(self):
+ """Should return False if they key is not in the dict."""
+ self.failIf(mox.ContainsKeyValue("qux", 1) == {"key": 2})
+
+
+class InTest(unittest.TestCase):
+ """Test In correctly identifies a key in a list/dict"""
+
+ def testItemInList(self):
+ """Should return True if the item is in the list."""
+ self.assert_(mox.In(1) == [1, 2, 3])
+
+ def testKeyInDict(self):
+ """Should return True if the item is a key in a dict."""
+ self.assert_(mox.In("test") == {"test" : "module"})
+
+
+class StrContainsTest(unittest.TestCase):
+ """Test StrContains correctly checks for substring occurrence of a parameter.
+ """
+
+ def testValidSubstringAtStart(self):
+ """Should return True if the substring is at the start of the string."""
+ self.assert_(mox.StrContains("hello") == "hello world")
+
+ def testValidSubstringInMiddle(self):
+ """Should return True if the substring is in the middle of the string."""
+ self.assert_(mox.StrContains("lo wo") == "hello world")
+
+ def testValidSubstringAtEnd(self):
+ """Should return True if the substring is at the end of the string."""
+ self.assert_(mox.StrContains("ld") == "hello world")
+
+ def testInvaildSubstring(self):
+ """Should return False if the substring is not in the string."""
+ self.failIf(mox.StrContains("AAA") == "hello world")
+
+ def testMultipleMatches(self):
+ """Should return True if there are multiple occurances of substring."""
+ self.assert_(mox.StrContains("abc") == "ababcabcabcababc")
+
+
+class RegexTest(unittest.TestCase):
+ """Test Regex correctly matches regular expressions."""
+
+ def testIdentifyBadSyntaxDuringInit(self):
+ """The user should know immediately if a regex has bad syntax."""
+ self.assertRaises(re.error, mox.Regex, '(a|b')
+
+ def testPatternInMiddle(self):
+ """Should return True if the pattern matches at the middle of the string.
+
+ This ensures that re.search is used (instead of re.find).
+ """
+ self.assert_(mox.Regex(r"a\s+b") == "x y z a b c")
+
+ def testNonMatchPattern(self):
+ """Should return False if the pattern does not match the string."""
+ self.failIf(mox.Regex(r"a\s+b") == "x y z")
+
+ def testFlagsPassedCorrectly(self):
+ """Should return True as we pass IGNORECASE flag."""
+ self.assert_(mox.Regex(r"A", re.IGNORECASE) == "a")
+
+ def testReprWithoutFlags(self):
+ """repr should return the regular expression pattern."""
+ self.assert_(repr(mox.Regex(r"a\s+b")) == "<regular expression 'a\s+b'>")
+
+ def testReprWithFlags(self):
+ """repr should return the regular expression pattern and flags."""
+ self.assert_(repr(mox.Regex(r"a\s+b", flags=4)) ==
+ "<regular expression 'a\s+b', flags=4>")
+
+
+class IsATest(unittest.TestCase):
+ """Verify IsA correctly checks equality based upon class type, not value."""
+
+ def testEqualityValid(self):
+ """Verify that == correctly identifies objects of the same type."""
+ self.assert_(mox.IsA(str) == 'test')
+
+ def testEqualityInvalid(self):
+ """Verify that == correctly identifies objects of different types."""
+ self.failIf(mox.IsA(str) == 10)
+
+ def testInequalityValid(self):
+ """Verify that != identifies objects of different type."""
+ self.assert_(mox.IsA(str) != 10)
+
+ def testInequalityInvalid(self):
+ """Verify that != correctly identifies objects of the same type."""
+ self.failIf(mox.IsA(str) != "test")
+
+ def testEqualityInListValid(self):
+ """Verify list contents are properly compared."""
+ isa_list = [mox.IsA(str), mox.IsA(str)]
+ str_list = ["abc", "def"]
+ self.assert_(isa_list == str_list)
+
+ def testEquailtyInListInvalid(self):
+ """Verify list contents are properly compared."""
+ isa_list = [mox.IsA(str),mox.IsA(str)]
+ mixed_list = ["abc", 123]
+ self.failIf(isa_list == mixed_list)
+
+ def testSpecialTypes(self):
+ """Verify that IsA can handle objects like cStringIO.StringIO."""
+ isA = mox.IsA(cStringIO.StringIO())
+ stringIO = cStringIO.StringIO()
+ self.assert_(isA == stringIO)
+
+class IsAlmostTest(unittest.TestCase):
+ """Verify IsAlmost correctly checks equality of floating point numbers."""
+
+ def testEqualityValid(self):
+ """Verify that == correctly identifies nearly equivalent floats."""
+ self.assertEquals(mox.IsAlmost(1.8999999999), 1.9)
+
+ def testEqualityInvalid(self):
+ """Verify that == correctly identifies non-equivalent floats."""
+ self.assertNotEquals(mox.IsAlmost(1.899), 1.9)
+
+ def testEqualityWithPlaces(self):
+ """Verify that specifying places has the desired effect."""
+ self.assertNotEquals(mox.IsAlmost(1.899), 1.9)
+ self.assertEquals(mox.IsAlmost(1.899, places=2), 1.9)
+
+ def testNonNumericTypes(self):
+ """Verify that IsAlmost handles non-numeric types properly."""
+
+ self.assertNotEquals(mox.IsAlmost(1.8999999999), '1.9')
+ self.assertNotEquals(mox.IsAlmost('1.8999999999'), 1.9)
+ self.assertNotEquals(mox.IsAlmost('1.8999999999'), '1.9')
+
+class MockMethodTest(unittest.TestCase):
+ """Test class to verify that the MockMethod class is working correctly."""
+
+ def setUp(self):
+ self.expected_method = mox.MockMethod("testMethod", [], False)(['original'])
+ self.mock_method = mox.MockMethod("testMethod", [self.expected_method],
+ True)
+
+ def testAndReturnNoneByDefault(self):
+ """Should return None by default."""
+ return_value = self.mock_method(['original'])
+ self.assert_(return_value == None)
+
+ def testAndReturnValue(self):
+ """Should return a specificed return value."""
+ expected_return_value = "test"
+ self.expected_method.AndReturn(expected_return_value)
+ return_value = self.mock_method(['original'])
+ self.assert_(return_value == expected_return_value)
+
+ def testAndRaiseException(self):
+ """Should raise a specified exception."""
+ expected_exception = Exception('test exception')
+ self.expected_method.AndRaise(expected_exception)
+ self.assertRaises(Exception, self.mock_method)
+
+ def testWithSideEffects(self):
+ """Should call state modifier."""
+ local_list = ['original']
+ def modifier(mutable_list):
+ self.assertTrue(local_list is mutable_list)
+ mutable_list[0] = 'mutation'
+ self.expected_method.WithSideEffects(modifier).AndReturn(1)
+ self.mock_method(local_list)
+ self.assertEquals('mutation', local_list[0])
+
+ def testEqualityNoParamsEqual(self):
+ """Methods with the same name and without params should be equal."""
+ expected_method = mox.MockMethod("testMethod", [], False)
+ self.assertEqual(self.mock_method, expected_method)
+
+ def testEqualityNoParamsNotEqual(self):
+ """Methods with different names and without params should not be equal."""
+ expected_method = mox.MockMethod("otherMethod", [], False)
+ self.failIfEqual(self.mock_method, expected_method)
+
+ def testEqualityParamsEqual(self):
+ """Methods with the same name and parameters should be equal."""
+ params = [1, 2, 3]
+ expected_method = mox.MockMethod("testMethod", [], False)
+ expected_method._params = params
+
+ self.mock_method._params = params
+ self.assertEqual(self.mock_method, expected_method)
+
+ def testEqualityParamsNotEqual(self):
+ """Methods with the same name and different params should not be equal."""
+ expected_method = mox.MockMethod("testMethod", [], False)
+ expected_method._params = [1, 2, 3]
+
+ self.mock_method._params = ['a', 'b', 'c']
+ self.failIfEqual(self.mock_method, expected_method)
+
+ def testEqualityNamedParamsEqual(self):
+ """Methods with the same name and same named params should be equal."""
+ named_params = {"input1": "test", "input2": "params"}
+ expected_method = mox.MockMethod("testMethod", [], False)
+ expected_method._named_params = named_params
+
+ self.mock_method._named_params = named_params
+ self.assertEqual(self.mock_method, expected_method)
+
+ def testEqualityNamedParamsNotEqual(self):
+ """Methods with the same name and diffnamed params should not be equal."""
+ expected_method = mox.MockMethod("testMethod", [], False)
+ expected_method._named_params = {"input1": "test", "input2": "params"}
+
+ self.mock_method._named_params = {"input1": "test2", "input2": "params2"}
+ self.failIfEqual(self.mock_method, expected_method)
+
+ def testEqualityWrongType(self):
+ """Method should not be equal to an object of a different type."""
+ self.failIfEqual(self.mock_method, "string?")
+
+ def testObjectEquality(self):
+ """Equality of objects should work without a Comparator"""
+ instA = TestClass();
+ instB = TestClass();
+
+ params = [instA, ]
+ expected_method = mox.MockMethod("testMethod", [], False)
+ expected_method._params = params
+
+ self.mock_method._params = [instB, ]
+ self.assertEqual(self.mock_method, expected_method)
+
+ def testStrConversion(self):
+ method = mox.MockMethod("f", [], False)
+ method(1, 2, "st", n1=8, n2="st2")
+ self.assertEqual(str(method), ("f(1, 2, 'st', n1=8, n2='st2') -> None"))
+
+ method = mox.MockMethod("testMethod", [], False)
+ method(1, 2, "only positional")
+ self.assertEqual(str(method), "testMethod(1, 2, 'only positional') -> None")
+
+ method = mox.MockMethod("testMethod", [], False)
+ method(a=1, b=2, c="only named")
+ self.assertEqual(str(method),
+ "testMethod(a=1, b=2, c='only named') -> None")
+
+ method = mox.MockMethod("testMethod", [], False)
+ method()
+ self.assertEqual(str(method), "testMethod() -> None")
+
+ method = mox.MockMethod("testMethod", [], False)
+ method(x="only 1 parameter")
+ self.assertEqual(str(method), "testMethod(x='only 1 parameter') -> None")
+
+ method = mox.MockMethod("testMethod", [], False)
+ method().AndReturn('return_value')
+ self.assertEqual(str(method), "testMethod() -> 'return_value'")
+
+ method = mox.MockMethod("testMethod", [], False)
+ method().AndReturn(('a', {1: 2}))
+ self.assertEqual(str(method), "testMethod() -> ('a', {1: 2})")
+
+
+class MockAnythingTest(unittest.TestCase):
+ """Verify that the MockAnything class works as expected."""
+
+ def setUp(self):
+ self.mock_object = mox.MockAnything()
+
+ def testSetupMode(self):
+ """Verify the mock will accept any call."""
+ self.mock_object.NonsenseCall()
+ self.assert_(len(self.mock_object._expected_calls_queue) == 1)
+
+ def testReplayWithExpectedCall(self):
+ """Verify the mock replays method calls as expected."""
+ self.mock_object.ValidCall() # setup method call
+ self.mock_object._Replay() # start replay mode
+ self.mock_object.ValidCall() # make method call
+
+ def testReplayWithUnexpectedCall(self):
+ """Unexpected method calls should raise UnexpectedMethodCallError."""
+ self.mock_object.ValidCall() # setup method call
+ self.mock_object._Replay() # start replay mode
+ self.assertRaises(mox.UnexpectedMethodCallError,
+ self.mock_object.OtherValidCall)
+
+ def testVerifyWithCompleteReplay(self):
+ """Verify should not raise an exception for a valid replay."""
+ self.mock_object.ValidCall() # setup method call
+ self.mock_object._Replay() # start replay mode
+ self.mock_object.ValidCall() # make method call
+ self.mock_object._Verify()
+
+ def testVerifyWithIncompleteReplay(self):
+ """Verify should raise an exception if the replay was not complete."""
+ self.mock_object.ValidCall() # setup method call
+ self.mock_object._Replay() # start replay mode
+ # ValidCall() is never made
+ self.assertRaises(mox.ExpectedMethodCallsError, self.mock_object._Verify)
+
+ def testSpecialClassMethod(self):
+ """Verify should not raise an exception when special methods are used."""
+ self.mock_object[1].AndReturn(True)
+ self.mock_object._Replay()
+ returned_val = self.mock_object[1]
+ self.assert_(returned_val)
+ self.mock_object._Verify()
+
+ def testNonzero(self):
+ """You should be able to use the mock object in an if."""
+ self.mock_object._Replay()
+ if self.mock_object:
+ pass
+
+ def testNotNone(self):
+ """Mock should be comparable to None."""
+ self.mock_object._Replay()
+ if self.mock_object is not None:
+ pass
+
+ if self.mock_object is None:
+ pass
+
+ def testEquals(self):
+ """A mock should be able to compare itself to another object."""
+ self.mock_object._Replay()
+ self.assertEquals(self.mock_object, self.mock_object)
+
+ def testEqualsMockFailure(self):
+ """Verify equals identifies unequal objects."""
+ self.mock_object.SillyCall()
+ self.mock_object._Replay()
+ self.assertNotEquals(self.mock_object, mox.MockAnything())
+
+ def testEqualsInstanceFailure(self):
+ """Verify equals identifies that objects are different instances."""
+ self.mock_object._Replay()
+ self.assertNotEquals(self.mock_object, TestClass())
+
+ def testNotEquals(self):
+ """Verify not equals works."""
+ self.mock_object._Replay()
+ self.assertFalse(self.mock_object != self.mock_object)
+
+ def testNestedMockCallsRecordedSerially(self):
+ """Test that nested calls work when recorded serially."""
+ self.mock_object.CallInner().AndReturn(1)
+ self.mock_object.CallOuter(1)
+ self.mock_object._Replay()
+
+ self.mock_object.CallOuter(self.mock_object.CallInner())
+
+ self.mock_object._Verify()
+
+ def testNestedMockCallsRecordedNested(self):
+ """Test that nested cals work when recorded in a nested fashion."""
+ self.mock_object.CallOuter(self.mock_object.CallInner().AndReturn(1))
+ self.mock_object._Replay()
+
+ self.mock_object.CallOuter(self.mock_object.CallInner())
+
+ self.mock_object._Verify()
+
+ def testIsCallable(self):
+ """Test that MockAnything can even mock a simple callable.
+
+ This is handy for "stubbing out" a method in a module with a mock, and
+ verifying that it was called.
+ """
+ self.mock_object().AndReturn('mox0rd')
+ self.mock_object._Replay()
+
+ self.assertEquals('mox0rd', self.mock_object())
+
+ self.mock_object._Verify()
+
+
+class MockObjectTest(unittest.TestCase):
+ """Verify that the MockObject class works as exepcted."""
+
+ def setUp(self):
+ self.mock_object = mox.MockObject(TestClass)
+
+ def testSetupModeWithValidCall(self):
+ """Verify the mock object properly mocks a basic method call."""
+ self.mock_object.ValidCall()
+ self.assert_(len(self.mock_object._expected_calls_queue) == 1)
+
+ def testSetupModeWithInvalidCall(self):
+ """UnknownMethodCallError should be raised if a non-member method is called.
+ """
+ # Note: assertRaises does not catch exceptions thrown by MockObject's
+ # __getattr__
+ try:
+ self.mock_object.InvalidCall()
+ self.fail("No exception thrown, expected UnknownMethodCallError")
+ except mox.UnknownMethodCallError:
+ pass
+ except Exception:
+ self.fail("Wrong exception type thrown, expected UnknownMethodCallError")
+
+ def testReplayWithInvalidCall(self):
+ """UnknownMethodCallError should be raised if a non-member method is called.
+ """
+ self.mock_object.ValidCall() # setup method call
+ self.mock_object._Replay() # start replay mode
+ # Note: assertRaises does not catch exceptions thrown by MockObject's
+ # __getattr__
+ try:
+ self.mock_object.InvalidCall()
+ self.fail("No exception thrown, expected UnknownMethodCallError")
+ except mox.UnknownMethodCallError:
+ pass
+ except Exception:
+ self.fail("Wrong exception type thrown, expected UnknownMethodCallError")
+
+ def testIsInstance(self):
+ """Mock should be able to pass as an instance of the mocked class."""
+ self.assert_(isinstance(self.mock_object, TestClass))
+
+ def testFindValidMethods(self):
+ """Mock should be able to mock all public methods."""
+ self.assert_('ValidCall' in self.mock_object._known_methods)
+ self.assert_('OtherValidCall' in self.mock_object._known_methods)
+ self.assert_('MyClassMethod' in self.mock_object._known_methods)
+ self.assert_('MyStaticMethod' in self.mock_object._known_methods)
+ self.assert_('_ProtectedCall' in self.mock_object._known_methods)
+ self.assert_('__PrivateCall' not in self.mock_object._known_methods)
+ self.assert_('_TestClass__PrivateCall' in self.mock_object._known_methods)
+
+ def testFindsSuperclassMethods(self):
+ """Mock should be able to mock superclasses methods."""
+ self.mock_object = mox.MockObject(ChildClass)
+ self.assert_('ValidCall' in self.mock_object._known_methods)
+ self.assert_('OtherValidCall' in self.mock_object._known_methods)
+ self.assert_('MyClassMethod' in self.mock_object._known_methods)
+ self.assert_('ChildValidCall' in self.mock_object._known_methods)
+
+ def testAccessClassVariables(self):
+ """Class variables should be accessible through the mock."""
+ self.assert_('SOME_CLASS_VAR' in self.mock_object._known_vars)
+ self.assert_('_PROTECTED_CLASS_VAR' in self.mock_object._known_vars)
+ self.assertEquals('test_value', self.mock_object.SOME_CLASS_VAR)
+
+ def testEquals(self):
+ """A mock should be able to compare itself to another object."""
+ self.mock_object._Replay()
+ self.assertEquals(self.mock_object, self.mock_object)
+
+ def testEqualsMockFailure(self):
+ """Verify equals identifies unequal objects."""
+ self.mock_object.ValidCall()
+ self.mock_object._Replay()
+ self.assertNotEquals(self.mock_object, mox.MockObject(TestClass))
+
+ def testEqualsInstanceFailure(self):
+ """Verify equals identifies that objects are different instances."""
+ self.mock_object._Replay()
+ self.assertNotEquals(self.mock_object, TestClass())
+
+ def testNotEquals(self):
+ """Verify not equals works."""
+ self.mock_object._Replay()
+ self.assertFalse(self.mock_object != self.mock_object)
+
+ def testMockSetItem_ExpectedSetItem_Success(self):
+ """Test that __setitem__() gets mocked in Dummy.
+
+ In this test, _Verify() succeeds.
+ """
+ dummy = mox.MockObject(TestClass)
+ dummy['X'] = 'Y'
+
+ dummy._Replay()
+
+ dummy['X'] = 'Y'
+
+ dummy._Verify()
+
+ def testMockSetItem_ExpectedSetItem_NoSuccess(self):
+ """Test that __setitem__() gets mocked in Dummy.
+
+ In this test, _Verify() fails.
+ """
+ dummy = mox.MockObject(TestClass)
+ dummy['X'] = 'Y'
+
+ dummy._Replay()
+
+ # NOT doing dummy['X'] = 'Y'
+
+ self.assertRaises(mox.ExpectedMethodCallsError, dummy._Verify)
+
+ def testMockSetItem_ExpectedNoSetItem_Success(self):
+ """Test that __setitem__() gets mocked in Dummy.
+
+ In this test, _Verify() succeeds.
+ """
+ dummy = mox.MockObject(TestClass)
+ # NOT doing dummy['X'] = 'Y'
+
+ dummy._Replay()
+
+ def call(): dummy['X'] = 'Y'
+ self.assertRaises(mox.UnexpectedMethodCallError, call)
+
+ dummy._Verify()
+
+ def testMockSetItem_ExpectedNoSetItem_NoSuccess(self):
+ """Test that __setitem__() gets mocked in Dummy.
+
+ In this test, _Verify() fails.
+ """
+ dummy = mox.MockObject(TestClass)
+ # NOT doing dummy['X'] = 'Y'
+
+ dummy._Replay()
+
+ # NOT doing dummy['X'] = 'Y'
+
+ dummy._Verify()
+
+ def testMockSetItem_ExpectedSetItem_NonmatchingParameters(self):
+ """Test that __setitem__() fails if other parameters are expected."""
+ dummy = mox.MockObject(TestClass)
+ dummy['X'] = 'Y'
+
+ dummy._Replay()
+
+ def call(): dummy['wrong'] = 'Y'
+
+ self.assertRaises(mox.UnexpectedMethodCallError, call)
+
+ dummy._Verify()
+
+ def testMockGetItem_ExpectedGetItem_Success(self):
+ """Test that __setitem__() gets mocked in Dummy.
+
+ In this test, _Verify() succeeds.
+ """
+ dummy = mox.MockObject(TestClass)
+ dummy['X'].AndReturn('value')
+
+ dummy._Replay()
+
+ self.assertEqual(dummy['X'], 'value')
+
+ dummy._Verify()
+
+ def testMockGetItem_ExpectedGetItem_NoSuccess(self):
+ """Test that __setitem__() gets mocked in Dummy.
+
+ In this test, _Verify() fails.
+ """
+ dummy = mox.MockObject(TestClass)
+ dummy['X'].AndReturn('value')
+
+ dummy._Replay()
+
+ # NOT doing dummy['X']
+
+ self.assertRaises(mox.ExpectedMethodCallsError, dummy._Verify)
+
+ def testMockGetItem_ExpectedNoGetItem_NoSuccess(self):
+ """Test that __setitem__() gets mocked in Dummy.
+
+ In this test, _Verify() succeeds.
+ """
+ dummy = mox.MockObject(TestClass)
+ # NOT doing dummy['X']
+
+ dummy._Replay()
+
+ def call(): return dummy['X']
+ self.assertRaises(mox.UnexpectedMethodCallError, call)
+
+ dummy._Verify()
+
+ def testMockGetItem_ExpectedGetItem_NonmatchingParameters(self):
+ """Test that __setitem__() fails if other parameters are expected."""
+ dummy = mox.MockObject(TestClass)
+ dummy['X'].AndReturn('value')
+
+ dummy._Replay()
+
+ def call(): return dummy['wrong']
+
+ self.assertRaises(mox.UnexpectedMethodCallError, call)
+
+ dummy._Verify()
+
+
+class MoxTest(unittest.TestCase):
+ """Verify Mox works correctly."""
+
+ def setUp(self):
+ self.mox = mox.Mox()
+
+ def testCreateObject(self):
+ """Mox should create a mock object."""
+ mock_obj = self.mox.CreateMock(TestClass)
+
+ def testVerifyObjectWithCompleteReplay(self):
+ """Mox should replay and verify all objects it created."""
+ mock_obj = self.mox.CreateMock(TestClass)
+ mock_obj.ValidCall()
+ mock_obj.ValidCallWithArgs(mox.IsA(TestClass))
+ self.mox.ReplayAll()
+ mock_obj.ValidCall()
+ mock_obj.ValidCallWithArgs(TestClass("some_value"))
+ self.mox.VerifyAll()
+
+ def testVerifyObjectWithIncompleteReplay(self):
+ """Mox should raise an exception if a mock didn't replay completely."""
+ mock_obj = self.mox.CreateMock(TestClass)
+ mock_obj.ValidCall()
+ self.mox.ReplayAll()
+ # ValidCall() is never made
+ self.assertRaises(mox.ExpectedMethodCallsError, self.mox.VerifyAll)
+
+ def testEntireWorkflow(self):
+ """Test the whole work flow."""
+ mock_obj = self.mox.CreateMock(TestClass)
+ mock_obj.ValidCall().AndReturn("yes")
+ self.mox.ReplayAll()
+
+ ret_val = mock_obj.ValidCall()
+ self.assertEquals("yes", ret_val)
+ self.mox.VerifyAll()
+
+ def testCallableObject(self):
+ """Test recording calls to a callable object works."""
+ mock_obj = self.mox.CreateMock(CallableClass)
+ mock_obj("foo").AndReturn("qux")
+ self.mox.ReplayAll()
+
+ ret_val = mock_obj("foo")
+ self.assertEquals("qux", ret_val)
+ self.mox.VerifyAll()
+
+ def testCallOnNonCallableObject(self):
+ """Test that you cannot call a non-callable object."""
+ mock_obj = self.mox.CreateMock(TestClass)
+ self.assertRaises(TypeError, mock_obj)
+
+ def testCallableObjectWithBadCall(self):
+ """Test verifying calls to a callable object works."""
+ mock_obj = self.mox.CreateMock(CallableClass)
+ mock_obj("foo").AndReturn("qux")
+ self.mox.ReplayAll()
+
+ self.assertRaises(mox.UnexpectedMethodCallError, mock_obj, "ZOOBAZ")
+
+ def testUnorderedGroup(self):
+ """Test that using one unordered group works."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Method(1).InAnyOrder()
+ mock_obj.Method(2).InAnyOrder()
+ self.mox.ReplayAll()
+
+ mock_obj.Method(2)
+ mock_obj.Method(1)
+
+ self.mox.VerifyAll()
+
+ def testUnorderedGroupsInline(self):
+ """Unordered groups should work in the context of ordered calls."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Open()
+ mock_obj.Method(1).InAnyOrder()
+ mock_obj.Method(2).InAnyOrder()
+ mock_obj.Close()
+ self.mox.ReplayAll()
+
+ mock_obj.Open()
+ mock_obj.Method(2)
+ mock_obj.Method(1)
+ mock_obj.Close()
+
+ self.mox.VerifyAll()
+
+ def testMultipleUnorderdGroups(self):
+ """Multiple unoreded groups should work."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Method(1).InAnyOrder()
+ mock_obj.Method(2).InAnyOrder()
+ mock_obj.Foo().InAnyOrder('group2')
+ mock_obj.Bar().InAnyOrder('group2')
+ self.mox.ReplayAll()
+
+ mock_obj.Method(2)
+ mock_obj.Method(1)
+ mock_obj.Bar()
+ mock_obj.Foo()
+
+ self.mox.VerifyAll()
+
+ def testMultipleUnorderdGroupsOutOfOrder(self):
+ """Multiple unordered groups should maintain external order"""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Method(1).InAnyOrder()
+ mock_obj.Method(2).InAnyOrder()
+ mock_obj.Foo().InAnyOrder('group2')
+ mock_obj.Bar().InAnyOrder('group2')
+ self.mox.ReplayAll()
+
+ mock_obj.Method(2)
+ self.assertRaises(mox.UnexpectedMethodCallError, mock_obj.Bar)
+
+ def testUnorderedGroupWithReturnValue(self):
+ """Unordered groups should work with return values."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Open()
+ mock_obj.Method(1).InAnyOrder().AndReturn(9)
+ mock_obj.Method(2).InAnyOrder().AndReturn(10)
+ mock_obj.Close()
+ self.mox.ReplayAll()
+
+ mock_obj.Open()
+ actual_two = mock_obj.Method(2)
+ actual_one = mock_obj.Method(1)
+ mock_obj.Close()
+
+ self.assertEquals(9, actual_one)
+ self.assertEquals(10, actual_two)
+
+ self.mox.VerifyAll()
+
+ def testUnorderedGroupWithComparator(self):
+ """Unordered groups should work with comparators"""
+
+ def VerifyOne(cmd):
+ if not isinstance(cmd, str):
+ self.fail('Unexpected type passed to comparator: ' + str(cmd))
+ return cmd == 'test'
+
+ def VerifyTwo(cmd):
+ return True
+
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Foo(['test'], mox.Func(VerifyOne), bar=1).InAnyOrder().\
+ AndReturn('yes test')
+ mock_obj.Foo(['test'], mox.Func(VerifyTwo), bar=1).InAnyOrder().\
+ AndReturn('anything')
+
+ self.mox.ReplayAll()
+
+ mock_obj.Foo(['test'], 'anything', bar=1)
+ mock_obj.Foo(['test'], 'test', bar=1)
+
+ self.mox.VerifyAll()
+
+ def testMultipleTimes(self):
+ """Test if MultipleTimesGroup works."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Method(1).MultipleTimes().AndReturn(9)
+ mock_obj.Method(2).AndReturn(10)
+ mock_obj.Method(3).MultipleTimes().AndReturn(42)
+ self.mox.ReplayAll()
+
+ actual_one = mock_obj.Method(1)
+ second_one = mock_obj.Method(1) # This tests MultipleTimes.
+ actual_two = mock_obj.Method(2)
+ actual_three = mock_obj.Method(3)
+ mock_obj.Method(3)
+ mock_obj.Method(3)
+
+ self.assertEquals(9, actual_one)
+ self.assertEquals(9, second_one) # Repeated calls should return same number.
+ self.assertEquals(10, actual_two)
+ self.assertEquals(42, actual_three)
+
+ self.mox.VerifyAll()
+
+ def testMultipleTimesUsingIsAParameter(self):
+ """Test if MultipleTimesGroup works with a IsA parameter."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Open()
+ mock_obj.Method(mox.IsA(str)).MultipleTimes("IsA").AndReturn(9)
+ mock_obj.Close()
+ self.mox.ReplayAll()
+
+ mock_obj.Open()
+ actual_one = mock_obj.Method("1")
+ second_one = mock_obj.Method("2") # This tests MultipleTimes.
+ mock_obj.Close()
+
+ self.assertEquals(9, actual_one)
+ self.assertEquals(9, second_one) # Repeated calls should return same number.
+
+ self.mox.VerifyAll()
+
+ def testMultipleTimesThreeMethods(self):
+ """Test if MultipleTimesGroup works with three or more methods."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Open()
+ mock_obj.Method(1).MultipleTimes().AndReturn(9)
+ mock_obj.Method(2).MultipleTimes().AndReturn(8)
+ mock_obj.Method(3).MultipleTimes().AndReturn(7)
+ mock_obj.Method(4).AndReturn(10)
+ mock_obj.Close()
+ self.mox.ReplayAll()
+
+ mock_obj.Open()
+ actual_three = mock_obj.Method(3)
+ mock_obj.Method(1)
+ actual_two = mock_obj.Method(2)
+ mock_obj.Method(3)
+ actual_one = mock_obj.Method(1)
+ actual_four = mock_obj.Method(4)
+ mock_obj.Close()
+
+ self.assertEquals(9, actual_one)
+ self.assertEquals(8, actual_two)
+ self.assertEquals(7, actual_three)
+ self.assertEquals(10, actual_four)
+
+ self.mox.VerifyAll()
+
+ def testMultipleTimesMissingOne(self):
+ """Test if MultipleTimesGroup fails if one method is missing."""
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Open()
+ mock_obj.Method(1).MultipleTimes().AndReturn(9)
+ mock_obj.Method(2).MultipleTimes().AndReturn(8)
+ mock_obj.Method(3).MultipleTimes().AndReturn(7)
+ mock_obj.Method(4).AndReturn(10)
+ mock_obj.Close()
+ self.mox.ReplayAll()
+
+ mock_obj.Open()
+ mock_obj.Method(3)
+ mock_obj.Method(2)
+ mock_obj.Method(3)
+ mock_obj.Method(3)
+ mock_obj.Method(2)
+
+ self.assertRaises(mox.UnexpectedMethodCallError, mock_obj.Method, 4)
+
+ def testMultipleTimesTwoGroups(self):
+ """Test if MultipleTimesGroup works with a group after a
+ MultipleTimesGroup.
+ """
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Open()
+ mock_obj.Method(1).MultipleTimes().AndReturn(9)
+ mock_obj.Method(3).MultipleTimes("nr2").AndReturn(42)
+ mock_obj.Close()
+ self.mox.ReplayAll()
+
+ mock_obj.Open()
+ actual_one = mock_obj.Method(1)
+ mock_obj.Method(1)
+ actual_three = mock_obj.Method(3)
+ mock_obj.Method(3)
+ mock_obj.Close()
+
+ self.assertEquals(9, actual_one)
+ self.assertEquals(42, actual_three)
+
+ self.mox.VerifyAll()
+
+ def testMultipleTimesTwoGroupsFailure(self):
+ """Test if MultipleTimesGroup fails with a group after a
+ MultipleTimesGroup.
+ """
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.Open()
+ mock_obj.Method(1).MultipleTimes().AndReturn(9)
+ mock_obj.Method(3).MultipleTimes("nr2").AndReturn(42)
+ mock_obj.Close()
+ self.mox.ReplayAll()
+
+ mock_obj.Open()
+ actual_one = mock_obj.Method(1)
+ mock_obj.Method(1)
+ actual_three = mock_obj.Method(3)
+
+ self.assertRaises(mox.UnexpectedMethodCallError, mock_obj.Method, 1)
+
+ def testWithSideEffects(self):
+ """Test side effect operations actually modify their target objects."""
+ def modifier(mutable_list):
+ mutable_list[0] = 'mutated'
+ mock_obj = self.mox.CreateMockAnything()
+ mock_obj.ConfigureInOutParameter(['original']).WithSideEffects(modifier)
+ mock_obj.WorkWithParameter(['mutated'])
+ self.mox.ReplayAll()
+
+ local_list = ['original']
+ mock_obj.ConfigureInOutParameter(local_list)
+ mock_obj.WorkWithParameter(local_list)
+
+ self.mox.VerifyAll()
+
+ def testWithSideEffectsException(self):
+ """Test side effect operations actually modify their target objects."""
+ def modifier(mutable_list):
+ mutable_list[0] = 'mutated'
+ mock_obj = self.mox.CreateMockAnything()
+ method = mock_obj.ConfigureInOutParameter(['original'])
+ method.WithSideEffects(modifier).AndRaise(Exception('exception'))
+ mock_obj.WorkWithParameter(['mutated'])
+ self.mox.ReplayAll()
+
+ local_list = ['original']
+ self.failUnlessRaises(Exception,
+ mock_obj.ConfigureInOutParameter,
+ local_list)
+ mock_obj.WorkWithParameter(local_list)
+
+ self.mox.VerifyAll()
+
+ def testStubOutMethod(self):
+ """Test that a method is replaced with a MockAnything."""
+ test_obj = TestClass()
+ # Replace OtherValidCall with a mock.
+ self.mox.StubOutWithMock(test_obj, 'OtherValidCall')
+ self.assert_(isinstance(test_obj.OtherValidCall, mox.MockAnything))
+ test_obj.OtherValidCall().AndReturn('foo')
+ self.mox.ReplayAll()
+
+ actual = test_obj.OtherValidCall()
+
+ self.mox.VerifyAll()
+ self.mox.UnsetStubs()
+ self.assertEquals('foo', actual)
+ self.failIf(isinstance(test_obj.OtherValidCall, mox.MockAnything))
+
+ def testStubOutObject(self):
+ """Test than object is replaced with a Mock."""
+
+ class Foo(object):
+ def __init__(self):
+ self.obj = TestClass()
+
+ foo = Foo()
+ self.mox.StubOutWithMock(foo, "obj")
+ self.assert_(isinstance(foo.obj, mox.MockObject))
+ foo.obj.ValidCall()
+ self.mox.ReplayAll()
+
+ foo.obj.ValidCall()
+
+ self.mox.VerifyAll()
+ self.mox.UnsetStubs()
+ self.failIf(isinstance(foo.obj, mox.MockObject))
+
+ def testForgotReplayHelpfulMessage(self):
+ """If there is an AttributeError on a MockMethod, give users a helpful msg.
+ """
+ foo = self.mox.CreateMockAnything()
+ bar = self.mox.CreateMockAnything()
+ foo.GetBar().AndReturn(bar)
+ bar.ShowMeTheMoney()
+ # Forgot to replay!
+ try:
+ foo.GetBar().ShowMeTheMoney()
+ except AttributeError, e:
+ self.assertEquals('MockMethod has no attribute "ShowMeTheMoney". '
+ 'Did you remember to put your mocks in replay mode?', str(e))
+
+class ReplayTest(unittest.TestCase):
+ """Verify Replay works properly."""
+
+ def testReplay(self):
+ """Replay should put objects into replay mode."""
+ mock_obj = mox.MockObject(TestClass)
+ self.assertFalse(mock_obj._replay_mode)
+ mox.Replay(mock_obj)
+ self.assertTrue(mock_obj._replay_mode)
+
+class MoxTestBaseTest(unittest.TestCase):
+ """Verify that all tests in a class derived from MoxTestBase are wrapped."""
+
+ def setUp(self):
+ self.mox = mox.Mox()
+ self.test_mox = mox.Mox()
+ 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()
+
+ def _setUpTestClass(self):
+ """Replacement for setUp in the test class instance.
+
+ Assigns a mox.Mox instance as the mox attribute of the test class instance.
+ This replacement Mox instance is under our control before setUp is called
+ in the test class instance.
+ """
+ self.test.mox = self.test_mox
+
+ def _CreateTest(self, test_name):
+ """Create a test from our example mox class.
+
+ The created test instance is assigned to this instances test attribute.
+ """
+ self.test = mox_test_helper.ExampleMoxTest(test_name)
+ self.mox.stubs.Set(self.test, 'setUp', self._setUpTestClass)
+
+ def _VerifySuccess(self):
+ """Run the checks to confirm test method completed successfully."""
+ self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs')
+ self.mox.StubOutWithMock(self.test_mox, 'VerifyAll')
+ self.test_mox.UnsetStubs()
+ self.test_mox.VerifyAll()
+ 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.test_mox.VerifyAll()
+
+ def testSuccess(self):
+ """Successful test method execution test."""
+ self._CreateTest('testSuccess')
+ self._VerifySuccess()
+
+ 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.test_mox.UnsetStubs()
+ self.test_mox.VerifyAll()
+ 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 testUnexpectedCall(self):
+ """Stubbed out method is called with unexpected arguments."""
+ self._CreateTest('testUnexpectedCall')
+ self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs')
+ # Ensure no calls are made to VerifyAll()
+ self.mox.StubOutWithMock(self.test_mox, 'VerifyAll')
+ self.test_mox.UnsetStubs()
+ 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')
+ # Ensure no calls are made to VerifyAll()
+ self.mox.StubOutWithMock(self.test_mox, 'VerifyAll')
+ self.test_mox.UnsetStubs()
+ 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."""
+ self._CreateTest('testStat')
+ self._VerifySuccess()
+
+ def testMixinAgain(self):
+ """Run same test as above but from the current test class.
+
+ This ensures metaclass properly wrapped test methods from all base classes.
+ If unsetting of stubs doesn't happen, this will fail.
+ """
+ self._CreateTest('testStatOther')
+ self._VerifySuccess()
+
+
+class VerifyTest(unittest.TestCase):
+ """Verify Verify works properly."""
+
+ def testVerify(self):
+ """Verify should be called for all objects.
+
+ This should throw an exception because the expected behavior did not occur.
+ """
+ mock_obj = mox.MockObject(TestClass)
+ mock_obj.ValidCall()
+ mock_obj._Replay()
+ self.assertRaises(mox.ExpectedMethodCallsError, mox.Verify, mock_obj)
+
+
+class ResetTest(unittest.TestCase):
+ """Verify Reset works properly."""
+
+ def testReset(self):
+ """Should empty all queues and put mocks in record mode."""
+ mock_obj = mox.MockObject(TestClass)
+ mock_obj.ValidCall()
+ self.assertFalse(mock_obj._replay_mode)
+ mock_obj._Replay()
+ self.assertTrue(mock_obj._replay_mode)
+ self.assertEquals(1, len(mock_obj._expected_calls_queue))
+
+ mox.Reset(mock_obj)
+ self.assertFalse(mock_obj._replay_mode)
+ self.assertEquals(0, len(mock_obj._expected_calls_queue))
+
+
+class TestClass:
+ """This class is used only for testing the mock framework"""
+
+ SOME_CLASS_VAR = "test_value"
+ _PROTECTED_CLASS_VAR = "protected value"
+
+ def __init__(self, ivar=None):
+ self.__ivar = ivar
+
+ def __eq__(self, rhs):
+ return self.__ivar == rhs
+
+ def __ne__(self, rhs):
+ return not self.__eq__(rhs)
+
+ def ValidCall(self):
+ pass
+
+ def OtherValidCall(self):
+ pass
+
+ def ValidCallWithArgs(self, *args, **kwargs):
+ pass
+
+ @classmethod
+ def MyClassMethod(cls):
+ pass
+
+ @staticmethod
+ def MyStaticMethod():
+ pass
+
+ def _ProtectedCall(self):
+ pass
+
+ def __PrivateCall(self):
+ pass
+
+ def __getitem__(self, key):
+ pass
+
+ def __DoNotMock(self):
+ pass
+
+ def __getitem__(self, key):
+ """Return the value for key."""
+ return self.d[key]
+
+ def __setitem__(self, key, value):
+ """Set the value for key to value."""
+ self.d[key] = value
+
+
+class ChildClass(TestClass):
+ """This inherits from TestClass."""
+ def __init__(self):
+ TestClass.__init__(self)
+
+ def ChildValidCall(self):
+ pass
+
+
+class CallableClass(object):
+ """This class is callable, and that should be mockable!"""
+
+ def __init__(self):
+ pass
+
+ def __call__(self, param):
+ return param
+
+
+if __name__ == '__main__':
+ unittest.main()