|
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
|