← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~allenap/maas/with-scenarios into lp:maas

 

Gavin Panella has proposed merging lp:~allenap/maas/with-scenarios into lp:maas.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~allenap/maas/with-scenarios/+merge/105988
-- 
https://code.launchpad.net/~allenap/maas/with-scenarios/+merge/105988
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/maas/with-scenarios into lp:maas.
=== added file 'src/maastesting/scenarios.py'
--- src/maastesting/scenarios.py	1970-01-01 00:00:00 +0000
+++ src/maastesting/scenarios.py	2012-05-16 14:36:18 +0000
@@ -0,0 +1,36 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Adapting `testscenarios` to work with MAAS."""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = [
+    "WithScenarios",
+    ]
+
+import testscenarios
+
+
+class WithScenarios(testscenarios.WithScenarios):
+    """Variant of testscenarios_' that provides ``__call__``.
+
+    Some sadistic `TestCase` implementations (cough, Django, cough) treat
+    ``__call__`` as something other than a synonym for ``run``. This means
+    that testscenarios_' ``WithScenarios``, which customises ``run`` only,
+    does not work correctly.
+
+    .. testscenarios_: https://launchpad.net/testscenarios
+    """
+
+    def __call__(self, result=None):
+        if self._get_scenarios():
+            for test in testscenarios.generate_scenarios(self):
+                test.__call__(result)
+        else:
+            super(WithScenarios, self).__call__(result)

=== modified file 'src/maastesting/testcase.py'
--- src/maastesting/testcase.py	2012-04-20 13:52:56 +0000
+++ src/maastesting/testcase.py	2012-05-16 14:36:18 +0000
@@ -18,19 +18,37 @@
 
 from fixtures import TempDir
 from maastesting.factory import factory
+from maastesting.scenarios import WithScenarios
 import testresources
 import testtools
 
 
-class TestCase(testtools.TestCase):
-    """Base `TestCase` for MAAS.  Supports test resources and fixtures."""
+class TestCase(WithScenarios, testtools.TestCase):
+    """Base `TestCase` for MAAS.
+
+    Supports `test resources`_, `test scenarios`_, and `fixtures`_.
+
+    .. _test resources: https://launchpad.net/testresources
+
+    .. _test scenarios: https://launchpad.net/testscenarios
+
+    .. _fixtures: https://launchpad.net/python-fixtures
+
+    """
+
     # testresources.ResourcedTestCase does something similar to this class
     # (with respect to setUpResources and tearDownResources) but it explicitly
     # up-calls to unittest.TestCase instead of using super() even though it is
     # not guaranteed that the next class in the inheritance chain is
     # unittest.TestCase.
 
-    resources = ()
+    resources = (
+        # (resource-name, resource),
+        )
+
+    scenarios = (
+        # (scenario-name, {instance-attribute-name: value, ...}),
+        )
 
     def setUp(self):
         super(TestCase, self).setUp()

=== added file 'src/maastesting/tests/test_scenarios.py'
--- src/maastesting/tests/test_scenarios.py	1970-01-01 00:00:00 +0000
+++ src/maastesting/tests/test_scenarios.py	2012-05-16 14:36:18 +0000
@@ -0,0 +1,68 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for `maastesting.scenarios`."""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = []
+
+import unittest
+
+from maastesting.scenarios import WithScenarios
+from maastesting.testcase import TestCase
+
+
+class TestWithScenarios(TestCase):
+
+    def test_scenarios_applied(self):
+        # Scenarios are applied correctly when a test is called via __call__()
+        # instead of run().
+
+        events = []
+
+        class Test(WithScenarios, unittest.TestCase):
+
+            scenarios = [
+                ("one", dict(token="one")),
+                ("two", dict(token="two")),
+                ]
+
+            def test(self):
+                events.append(self.token)
+
+        test = Test("test")
+        test.__call__()
+
+        self.assertEqual(["one", "two"], events)
+
+    def test_scenarios_applied_by_call(self):
+        # Scenarios are applied by __call__() when it is called first, and not
+        # by run().
+
+        events = []
+
+        class Test(WithScenarios, unittest.TestCase):
+
+            scenarios = [
+                ("one", dict(token="one")),
+                ("two", dict(token="two")),
+                ]
+
+            def test(self):
+                events.append(self.token)
+
+            def run(self, result=None):
+                # Call-up right past WithScenarios.run() to show that it is
+                # not responsible for applying scenarios, and __call__() is.
+                super(WithScenarios, self).run(result)
+
+        test = Test("test")
+        test.__call__()
+
+        self.assertEqual(["one", "two"], events)