launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #09587
[Merge] lp:~jtv/maas/fakemethod into lp:maas
Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/fakemethod into lp:maas.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~jtv/maas/fakemethod/+merge/113505
This is just too handy to keep doing without — I found myself stuck with ugly closures in another branch, trying to kludge around not having it.
I copied the module pretty much verbatim from Launchpad. Yes, that risks forking. But we haven't changed it in years, and it's far too small to stand on its own as a project. (If it were, it would be harder to come to grips with and we might not even bother using it).
Jeroen
--
https://code.launchpad.net/~jtv/maas/fakemethod/+merge/113505
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/maas/fakemethod into lp:maas.
=== added file 'src/maastesting/fakemethod.py'
--- src/maastesting/fakemethod.py 1970-01-01 00:00:00 +0000
+++ src/maastesting/fakemethod.py 2012-07-05 07:43:19 +0000
@@ -0,0 +1,72 @@
+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+# pylint: disable-msg=E0702
+
+"""Test helper, copied from the Launchpad source tree."""
+
+from __future__ import (
+ absolute_import,
+ print_function,
+ unicode_literals,
+ )
+
+__metaclass__ = type
+__all__ = [
+ 'FakeMethod',
+ ]
+
+
+class FakeMethod:
+ """Catch any function or method call, and record the fact.
+
+ Use this for easy stubbing. The call operator can return a fixed
+ value, or raise a fixed exception object.
+
+ This is useful when unit-testing code that does things you don't
+ want to integration-test, e.g. because it wants to talk to remote
+ systems.
+ """
+
+ def __init__(self, result=None, failure=None):
+ """Set up a fake function or method.
+
+ :param result: Value to return.
+ :param failure: Exception to raise.
+ """
+ self.result = result
+ self.failure = failure
+
+ # A log of arguments for each call to this method.
+ self.calls = []
+
+ def __call__(self, *args, **kwargs):
+ """Catch an invocation to the method.
+
+ Increment `call_count`, and adds the arguments to `calls`.
+
+ Accepts any and all parameters. Raises the failure passed to
+ the constructor, if any; otherwise, returns the result value
+ passed to the constructor.
+ """
+ self.calls.append((args, kwargs))
+
+ if self.failure is None:
+ return self.result
+ else:
+ # pylint thinks this raises None, which is clearly not
+ # possible. That's why this test disables pylint message
+ # E0702.
+ raise self.failure
+
+ @property
+ def call_count(self):
+ return len(self.calls)
+
+ def extract_args(self):
+ """Return just the calls' positional-arguments tuples."""
+ return [args for args, kwargs in self.calls]
+
+ def extract_kwargs(self):
+ """Return just the calls' keyword-arguments dicts."""
+ return [kwargs for args, kwargs in self.calls]
=== added file 'src/maastesting/tests/test_fakemethod.py'
--- src/maastesting/tests/test_fakemethod.py 1970-01-01 00:00:00 +0000
+++ src/maastesting/tests/test_fakemethod.py 2012-07-05 07:43:19 +0000
@@ -0,0 +1,51 @@
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for :class:`FakeMethod`."""
+
+from __future__ import (
+ absolute_import,
+ print_function,
+ unicode_literals,
+ )
+
+__metaclass__ = type
+__all__ = []
+
+from maastesting.fakemethod import FakeMethod
+from maastesting.testcase import TestCase
+
+
+class TestFakeMethod(TestCase):
+
+ def test_fakemethod_returns_None_by_default(self):
+ self.assertEqual(None, FakeMethod()())
+
+ def test_fakemethod_returns_given_value(self):
+ self.assertEqual("Input value", FakeMethod("Input value")())
+
+ def test_fakemethod_raises_given_failure(self):
+ class ExpectedException(Exception):
+ pass
+
+ self.assertRaises(
+ ExpectedException,
+ FakeMethod(failure=ExpectedException()))
+
+ def test_fakemethod_has_no_calls_initially(self):
+ self.assertSequenceEqual([], FakeMethod().calls)
+
+ def test_fakemethod_records_call(self):
+ stub = FakeMethod()
+ stub()
+ self.assertSequenceEqual([((), {})], stub.calls)
+
+ def test_fakemethod_records_args(self):
+ stub = FakeMethod()
+ stub(1, 2)
+ self.assertSequenceEqual([((1, 2), {})], stub.calls)
+
+ def test_fakemethod_records_kwargs(self):
+ stub = FakeMethod()
+ stub(x=10)
+ self.assertSequenceEqual([((), {'x': 10})], stub.calls)