From: Fredrik Wendt Date: Mon, 23 Aug 2010 21:44:39 +0000 (+0100) Subject: wrote simple mocking helper methods and classes X-Git-Url: http://git.maemo.org/git/?p=wifi-assistant;a=commitdiff_plain;h=8b9643a60153e0054fc7342bcacb71c6ae073944 wrote simple mocking helper methods and classes --- diff --git a/package/test/unit/pie.py b/package/test/unit/pie.py new file mode 100644 index 0000000..e605b28 --- /dev/null +++ b/package/test/unit/pie.py @@ -0,0 +1,181 @@ +import sys + +def pprint(*args): + if False: + for a in args: + try: + sys.stdout.write(a.__str__()) + except: + try: + sys.stdout.write(a.__doc__) + except: + sys.stdout.write('BUG - FIXME') + sys.stdout.write(' ') + sys.stdout.write('\n') + sys.stdout.flush() + +class Mock(): + def __init__(self): + pprint("Mock.__init__") + self._methods = {} + self._replay = False + + def __getattr__(self, value): + pprint("Mock.__getattr__", value) + if self._methods.has_key(value): + pprint("returning mocked method") + return self._methods[value] + if self._replay: + class inner(): + def __init__(self, method_name): + self._method_name = method_name + self._recorded_calls = [] + self._args = None + self._kwargs = None + def __call__(self, *args, **kwargs): + pprint("REPLAYING", self.getName(), args, kwargs) + self._recorded_calls.append((args, kwargs)) + self._args = args + self._kwargs = kwargs + def getName(self): + return self._method_name + def getNumberOfInvocations(self): + return len(self._recorded_calls) + def verify(self, args, kwargs): + if args != self._args or kwargs != self._kwargs: + raise Exception("No call for %s with arguments %s - actual: %s" % (value, args, self._args)) + return True + + pprint("returning 'empty' method", value) + empty = inner(value) + self.register(value, empty) + return empty + raise AttributeError("Mock doesn't contain attribute", value) + pprint("returning super method") + return Object.__getattr__.call(self, value) + + def replay(self): + pprint("Mock.__replay__") + self._replay = True + + def register(self, methodName, mock): + pprint("Mock.__register__", methodName) + self._methods[methodName] = mock + + def getMethodMock(self, methodName): + pprint("Mock.getMethodMock", methodName) + if self._methods.has_key(methodName): + return self._methods[methodName] + return None + +class MethodMock(): + def __init__(self, mock, args, kwargs): + pprint("MethodMock.__init__", args, kwargs) + self.target = mock + self._method_name = args[0] + mock.register(self._method_name, self) + self.args = args[1:] + self.kwargs = kwargs + self._recorded_calls = [] + self._canned_response = None + self._canned_args = None + self._canned_args_set = False + + def willReturn(self, args): + pprint(self.getName(), "willReturn", args) + self._canned_response = args + + def verify(self, args, kwargs): + pprint("MethodMock.verify", args, kwargs) + recorded_args, recorded_kwargs = self._recorded_calls.pop() + pprint(" .verify", recorded_args, recorded_kwargs) + return args == recorded_args and kwargs == recorded_kwargs + + def getName(self): + return self._method_name + + def getNumberOfInvocations(self): + return len(self._recorded_calls) + + def __call__(self, *args, **kwargs): + if self._canned_args_set: # replay + pprint("MethodMock.__call__ REPLAYING", self.getName(), args, kwargs, "returning", self._canned_response) + self._recorded_calls.append((args, kwargs)) + return self._canned_response + else: + pprint("MethodMock.__call__ RECORDING", self.getName(), args, kwargs) + self._canned_args_set = True + self._canned_args = args + return self + +class given(): + def __init__(self, mock): + pprint("given.__init__") + self.target = mock + + def __getattr__(self, *args, **kwargs): + pprint("given.__getattr__", args, kwargs) + return MethodMock(self.target, args, kwargs) + + +class MethodCallVerifier(): + def __init__(self, methodMock, times): + self.method = methodMock + self.times = times + def __call__(self, *args, **kwargs): + pprint("MethodCallVerifier.__call__", self.method, args, kwargs) + # FIXME: verify times times + calls = self.method.getNumberOfInvocations() + min_calls = self.times.getMinimumNumberOfTimes() + max_calls = self.times.getMaximumNumberOfTimes() + if calls < min_calls: + raise Exception("Expected at least %s calls to %s, got %s" % (min_calls, self.method.getName(), calls)) + if calls > max_calls: + raise Exception("Expected at most %s calls to %s, got %s" % (max_calls, self.method.getName(), calls)) + if calls == 0: + return + + match = self.method.verify(args, kwargs) + if match: + pprint("Yes, call for", self.method.getName(), "matched arguments", args, kwargs) + else: + pprint("Nope, call for", self.method.getName(), "didn't match arguments", args, kwargs) + raise Exception("mock verification failed") + +def empty(*args, **kwargs): + pass + +class once(): + def __call__(self): + pass + def getMinimumNumberOfTimes(self): + return 1 + def getMaximumNumberOfTimes(self): + return 1 + +class never(): + def __call__(self): + pass + def getMinimumNumberOfTimes(self): + return 0 + def getMaximumNumberOfTimes(self): + return 0 + +class verify(): + def __init__(self, mock, times=None): + pprint("verify.__init__") + self.target = mock + self.times = times + if self.times is None: + self.times = once() + + def __getattr__(self, methodName): + pprint("verify.__getattr__", methodName) + method_mock = self.target.getMethodMock(methodName) + if method_mock is None: + if self.times.getMinimumNumberOfTimes() > 0: + raise Exception("method " + methodName + " was never called") + return empty + return MethodCallVerifier(method_mock, self.times) + + diff --git a/package/test/unit/test_pie.py b/package/test/unit/test_pie.py new file mode 100644 index 0000000..dcb60a8 --- /dev/null +++ b/package/test/unit/test_pie.py @@ -0,0 +1,48 @@ +import unittest +from pie import * + + +class TestPie(unittest.TestCase): + + def test_never(self): + mock = Mock() + mock.replay() + verify(mock, never()).fakeMethod() + + def test_neverFail(self): + mock = Mock() + mock.replay() + mock.fakeMethod() + try: + verify(mock, never()).fakeMethod() + raise Exception("The fake method was called - the verify statement should fail") + except: + pass + + def test_onceSuccess(self): + mock = Mock() + given(mock).method().willReturn(True) + mock.replay() + result = mock.method() + assert result is True + verify(mock, once()).method() + + def test_onceFail(self): + mock = Mock() + given(mock).method().willReturn(True) + mock.replay() + try: + verify(mock, once()).method() + raise Exception("The method was never called - the verify step should fail") + except: + pass + + def test_implicitOnce_undefinedReturn_WithArguments(self): + mock = Mock() + mock.replay() + url = 'http://sample.argument' + mock.openUrl(url) + verify(mock).openUrl(url) + +if __name__ == '__main__': + unittest.main()