From: <bl...@us...> - 2003-05-29 14:05:58
|
Update of /cvsroot/cpptool/rfta/src/pyrfta/test/mock In directory sc8-pr-cvs1:/tmp/cvs-serv13378/test/mock Added Files: MockFactory.py Test_MockFactory.py __init__.py Log Message: * added initial structure for python extension --- NEW FILE: MockFactory.py --- class MockMethod(object): def __init__(self, instance, methodName, realMethod): object.__init__(self) self.__name__ = methodName self.instance = instance self.method = getattr(instance, methodName) self.realMethod = realMethod self.kwargsPassed = [] self.argsPassed = [] def setExpectNoCall( self ): self.setException( AssertionError( "Expected no call." ) ) def setException(self, exception): self.eventSequence = [exception] def setReturnValue(self, value): self.eventSequence = [value] def setEventSequence(self, seq): self.eventSequence = seq[:] def __call__(self, *args, **kwargs): # Can we check the mock method has a similar interface to the real method? ## hide private methods from caller self.instance.called.append(self.__name__) self.argsPassed.append(args) self.kwargsPassed.append(kwargs) # default to returning None (if u don;t do anything) obj = None if self.realMethod: obj = self.realMethod(*args, **kwargs) if hasattr(self, "eventSequence"): try: obj = self.eventSequence.pop(0) except IndexError, ie: raise ie else: if isinstance(obj, Exception): raise obj return obj class MockFactory(object): def __new__(classDef, mockMethods, *args, **kwargs): self = classDef(*args, **kwargs) self.called = [] ## ensure specified methods are avaiaible callables = [ name for name in dir(self) if callable(getattr(self, name)) ] for m in mockMethods: if not m in callables: raise AttributeError("Specified mock method (%s)does not exist" % m) ## override this instances attributes for name in dir(self): attr = getattr(self, name) if name.startswith("__") and not name.endswith("__") or name=='called': continue elif callable(attr): if name in mockMethods: real = None else: real = attr setattr(self, name, MockMethod(self, name, real)) elif attr is None and name not in mockMethods and \ not (name.startswith("__") and name.endswith("__")): raise AttributeError("Cannot mock undefined instance variable (%s)" % name) else: setattr(self, name, attr) return self --- NEW FILE: Test_MockFactory.py --- import unittest from MockFactory import MockFactory, MockMethod class TestClass: "test" y=2 def __init__(self): self.x=1 def do(self, *args, **kwargs): return 1 def dont(self): return 2 def a(self): pass def b(self): pass def c(self): raise Exception("test") def d(self, x=1): print x def e(self, a,b,c=2,d=3): pass def main(self): self.do(1) self.dont() self.a() self.b() try: res = self.c() except Exception, e: print e res = self.dont() return res class TestClass2(TestClass): def __init__(self, a,b,c,d={}): TestClass.__init__(self) class TestClass3(TestClass): pass class AcceptMockFactory(unittest.TestCase): # nb. this method is named duiffently to show we are not testing a method of the mock object class def testAttributes(self): """prove mock object is the *same* object as the "real" class""" mockInstance = MockFactory.__new__(TestClass, []) self.assertEqual(mockInstance.y, 2) mockInstance.y = 5 self.assertEqual(mockInstance.y, 5) self.assertEqual(TestClass.y, 2) TestClass.y = 100 self.assertEqual(TestClass.y, 100) def testMethods(self): """prove a mock object's methods are all instances of MockMethod""" mockInstance = MockFactory.__new__(TestClass, []) callables = [ getattr(mockInstance, n) for n in dir(mockInstance) if callable(getattr(mockInstance, n)) and not n=="__init__" ] for method in callables: #just check that doen't raise method.setEventSequence(['anything']) self.assertRaises(AttributeError, MockFactory.__new__, TestClass3, ["a", "d", "quit"]) mockInstance = MockFactory.__new__(TestClass3, ["a", "d"]) self.failUnless(isinstance(mockInstance.a, MockMethod)) self.failUnless(isinstance(mockInstance.d, MockMethod)) class TestMockFactory(unittest.TestCase): def testConstruction(self): "Test that the mock object's constructor is valid" self.assertRaises(TypeError, MockFactory.__new__, TestClass2, []) self.assertRaises(TypeError, MockFactory.__new__, TestClass2, [], 1,2) self.assertRaises(TypeError, MockFactory.__new__, TestClass2, [], 1,2,3,e={1:1}) MockFactory.__new__(TestClass2, [], 1,2,3) MockFactory.__new__(TestClass2, [], 1,2,3,d={1:2}) ## add test for raising contructor def testCalled(self): "Test that we can find out what methods have been called on the mock object" tests = [(TestClass, [], ["main", "do", "dont", "a", "b", "c", "dont"]), (TestClass, ['c'], ["main", "do", "dont", "a", "b", "c"]), (TestClass3, [], ["main", "do", "dont", "a", "b", "c", "dont"]) ] for (testKlass, mockMethods, expected) in tests: mockObject = MockFactory.__new__(testKlass, mockMethods) mockObject.main() actual = mockObject.called self.assertEqual(actual,expected) class TestMockMethod(unittest.TestCase): def testSetException(self): "Simulate a method raising an exception" mockObject = MockFactory.__new__(TestClass, []) mockObject.a.setException(IOError("deliberate exception")) self.assertRaises(IOError, mockObject.a) def testSetReturnValue(self): "Simulate a method returning something" mockObject = MockFactory.__new__(TestClass, []) self.assertEqual(mockObject.dont(), 2) expected = "123" mockObject.dont.setReturnValue(expected) self.assertEqual(mockObject.dont(), expected) def testArgsPassed(self): "Get the arguments passed to a method" expected = [(123, "test"),(1123123,), ("matt",)] mockObject = MockFactory.__new__(TestClass, []) for args in expected: apply(mockObject.do, args) self.assertEqual(mockObject.do.argsPassed, expected) def testKwargsPassed(self): "Get the keyword arguments passed to a method" expected = [{"test":1},{"default":2}, {"3":4}] mockObject = MockFactory.__new__(TestClass, ["a", "b", "c"]) for kwargs in expected: apply(mockObject.do, [], kwargs) self.assertEqual(mockObject.do.kwargsPassed, expected) def testSetEventSequence(self): "Set a list of events that a method will return/raise upon invokation" events = [Exception("delibratly raised"), "some return value", IOError("Another raise"), None, "another return value"] mockObject = MockFactory.__new__(TestClass, []) mockObject.a.setEventSequence(events) for event in events: if isinstance(event, Exception): self.assertRaises(event.__class__, mockObject.a) else: self.assertEqual(mockObject.a(), event) self.assertRaises(IndexError, mockObject.a) class TestTestCaseUsage(unittest.TestCase): def testCreateMockInstance(self): x=self.createMockInstance(TestClass,[]) y=MockFactory.__new__(TestClass,[]) self.assertEqual(dir(x),dir(y)) if __name__=="__main__": unittest.main() --- NEW FILE: __init__.py --- import unittest from MockFactory import MockFactory def _createMockInstance( self, classType, methods=[], *initArgs, **initKwargs): """Create a mock instance of specified type (classType) See MockFactory.py for more detail """ return MockFactory.__new__( classType, methods, *initArgs, **initKwargs ) unittest.TestCase.createMockInstance = _createMockInstance |