summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Collins <robertc@robertcollins.net>2009-06-17 19:11:03 +1000
committerRobert Collins <robertc@robertcollins.net>2009-06-17 19:11:03 +1000
commitb571a618c617fb02805731eab238baa75c5a4179 (patch)
treeee118fc2ce35a14d46e2c6852ec73e66286929a5
parent517ce1f70cb7a969b808a0445dd75c278f61ff69 (diff)
parent58b817afeb8b95e35d5a6347266316b9f35a3465 (diff)
downloadtestresources-b571a618c617fb02805731eab238baa75c5a4179.tar.gz
Merge adsorbSuite->addTests rename.
-rw-r--r--NEWS7
-rw-r--r--README8
-rw-r--r--TODO24
-rw-r--r--lib/testresources/__init__.py39
-rw-r--r--lib/testresources/tests/test_optimising_test_suite.py57
-rwxr-xr-xtest_all.py2
6 files changed, 80 insertions, 57 deletions
diff --git a/NEWS b/NEWS
index 3692fce..05fabb2 100644
--- a/NEWS
+++ b/NEWS
@@ -31,6 +31,13 @@ IN DEVELOPMENT
API CHANGES:
+ * adsorbSuite is now deprecated in favour of addTest. addTest now flattens
+ standard library TestSuites and distributes custom TestSuite across
+ their member tests. (Jonathan Lange)
+
+ * ResourcedTestCase.setUpResources and tearDownResources are now instance
+ methods, not static methods. (Jonathan Lange)
+
* All methods on TestResource are now instance methods, and thus tests
should use instances of TestResource subclasses, not the classes
themselves. (Jonathan Lange)
diff --git a/README b/README
index 69a28a5..d47c586 100644
--- a/README
+++ b/README
@@ -73,9 +73,11 @@ minimise the number of setup and tear downs required. It attempts to achieve
this by callling getResource() and finishedWith() around the sequence of tests
that use a specific resource.
-OptimisingTestSuite has a new method over normal TestSuites:
-adsorbSuite(test_case_or_suite), which scans another test suite and
-incorporates all of its tests directly into the OptimisingTestSuite.
+Tests are added to an OptimisingTestSuite as normal. Any standard library
+TestSuite objects will be flattened, while any custom TestSuite subclasses
+will be distributed across their member tests. This means that any custom
+logic in test suites should be preserved, at the price of some level of
+optimisation.
Because the test suite does the optimisation, you can control the amount of
optimising that takes place by adding more or fewer tests to a single
diff --git a/TODO b/TODO
index e654fe7..8534465 100644
--- a/TODO
+++ b/TODO
@@ -50,30 +50,6 @@ Ideas
* There are now many simple test helpers. These can probably be consolidated.
-* We want to support adding other "special" test suites to
- OptimisingTestSuite. In particular, if we add a test suite that provides
- services to its tests to an OptimisingTestSuite, adsorbSuite should not
- totally flatten the suite, but instead keep the suite, even if it changes
- the structure of the tests.
-
- e.g. addTest maintains the structure:
- >>> OptimisingTestSuite().addTest(SpecialSuite([a, b]))._tests
- [SpecialSuite([a, b])]
-
- Currently, adsorbSuite destroys all suite structure:
- >>> OptimisingTestSuite().adsorbSuite(SpecialSuite([a, b]))._tests
- [a, b]
-
- Instead, it should preserve the suite while changing the structure:
- >>> OptimisingTestSuite().adsorbSuite(SpecialSuite([a, b]))._tests
- [SpecialSuite(a), SpecialSuite(b)]
-
- All of the tests in each of the resulting new SpecialSuites should have
- identical resource requirements so we can still optimise.
-
- Once it does this, we should deprecate adsorbSuite and move this
- functionality to addTest / addTests.
-
* 'TestResource' isn't a very good name. Since the switch to instance-based
resources, it's even worse, since the objects are more like resource
factories or resource managers. Other possible names involve 'asset',
diff --git a/lib/testresources/__init__.py b/lib/testresources/__init__.py
index 2f317ea..5a5aa15 100644
--- a/lib/testresources/__init__.py
+++ b/lib/testresources/__init__.py
@@ -25,18 +25,6 @@ def test_suite():
return testresources.tests.test_suite()
-def iterate_tests(test_suite_or_case):
- """Iterate through all of the test cases in `test_suite_or_case`."""
- try:
- suite = iter(test_suite_or_case)
- except TypeError:
- yield test_suite_or_case
- else:
- for test in suite:
- for subtest in iterate_tests(test):
- yield subtest
-
-
def split_by_resources(tests):
"""Split a list of tests by the resources that the tests use.
@@ -60,14 +48,29 @@ class OptimisingTestSuite(unittest.TestSuite):
"""A resource creation optimising TestSuite."""
def adsorbSuite(self, test_case_or_suite):
- """Add `test_case_or_suite`, unwrapping any suites we find.
+ """Deprecated. Use addTest instead."""
+ self.addTest(test_case_or_suite)
+
+ def addTest(self, test_case_or_suite):
+ """Add `test_case_or_suite`, unwrapping standard TestSuites.
- This means that any containing TestSuites will be removed. These
- suites might have their own unittest extensions, so be careful with
- this.
+ This means that any containing unittest.TestSuites will be removed,
+ while any custom test suites will be 'distributed' across their
+ members. Thus addTest(CustomSuite([a, b])) will result in
+ CustomSuite([a]) and CustomSuite([b]) being added to this suite.
"""
- for test in iterate_tests(test_case_or_suite):
- self.addTest(test)
+ try:
+ tests = iter(test_case_or_suite)
+ except TypeError:
+ unittest.TestSuite.addTest(self, test_case_or_suite)
+ return
+ if unittest.TestSuite == test_case_or_suite.__class__:
+ for test in tests:
+ self.adsorbSuite(test)
+ else:
+ for test in tests:
+ unittest.TestSuite.addTest(
+ self, test_case_or_suite.__class__([test]))
def cost_of_switching(self, old_resource_set, new_resource_set):
"""Cost of switching from 'old_resource_set' to 'new_resource_set'.
diff --git a/lib/testresources/tests/test_optimising_test_suite.py b/lib/testresources/tests/test_optimising_test_suite.py
index 4bf06d3..fddbb5f 100644
--- a/lib/testresources/tests/test_optimising_test_suite.py
+++ b/lib/testresources/tests/test_optimising_test_suite.py
@@ -32,6 +32,16 @@ def test_suite():
return result
+class CustomSuite(unittest.TestSuite):
+ """Custom TestSuite that's comparable using == and !=."""
+
+ def __eq__(self, other):
+ return (self.__class__ == other.__class__
+ and self._tests == other._tests)
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
class MakeCounter(testresources.TestResource):
"""Test resource that counts makes and cleans."""
@@ -71,33 +81,58 @@ class TestOptimisingTestSuite(testtools.TestCase):
testtools.TestCase.setUp(self)
self.optimising_suite = testresources.OptimisingTestSuite()
- def testAdsorbTest(self):
- # Adsorbing a single test case is the same as adding one using
- # addTest.
+ def testAddTest(self):
+ # Adding a single test case is the same as adding one using the
+ # standard addTest.
case = self.makeTestCase()
- self.optimising_suite.adsorbSuite(case)
+ self.optimising_suite.addTest(case)
self.assertEqual([case], self.optimising_suite._tests)
- def testAdsorbTestSuite(self):
- # Adsorbing a test suite will is the same as adding all the tests in
+ def testAddTestSuite(self):
+ # Adding a standard test suite is the same as adding all the tests in
# that suite.
case = self.makeTestCase()
suite = unittest.TestSuite([case])
- self.optimising_suite.adsorbSuite(suite)
+ self.optimising_suite.addTest(suite)
self.assertEqual([case], self.optimising_suite._tests)
- def testAdsorbFlattensAllSuiteStructure(self):
- # adsorbSuite will get rid of all suite structure when adding a test,
- # no matter how much nesting is going on.
+ def testAddFlattensStandardSuiteStructure(self):
+ # addTest will get rid of all unittest.TestSuite structure when adding
+ # a test, no matter how much nesting is going on.
case1 = self.makeTestCase()
case2 = self.makeTestCase()
case3 = self.makeTestCase()
suite = unittest.TestSuite(
[unittest.TestSuite([case1, unittest.TestSuite([case2])]),
case3])
- self.optimising_suite.adsorbSuite(suite)
+ self.optimising_suite.addTest(suite)
self.assertEqual([case1, case2, case3], self.optimising_suite._tests)
+ def testAddDistributesNonStandardSuiteStructure(self):
+ # addTest distributes all non-standard TestSuites across their
+ # members.
+ case1 = self.makeTestCase()
+ case2 = self.makeTestCase()
+ inner_suite = unittest.TestSuite([case2])
+ suite = CustomSuite([case1, inner_suite])
+ self.optimising_suite.addTest(suite)
+ self.assertEqual(
+ [CustomSuite([case1]), CustomSuite([inner_suite])],
+ self.optimising_suite._tests)
+
+ def testAddPullsNonStandardSuitesUp(self):
+ # addTest flattens standard TestSuites, even those that contain custom
+ # suites. When it reaches the custom suites, it distributes them
+ # across their members.
+ case1 = self.makeTestCase()
+ case2 = self.makeTestCase()
+ inner_suite = CustomSuite([case1, case2])
+ self.optimising_suite.addTest(
+ unittest.TestSuite([unittest.TestSuite([inner_suite])]))
+ self.assertEqual(
+ [CustomSuite([case1]), CustomSuite([case2])],
+ self.optimising_suite._tests)
+
def testSingleCaseResourceAcquisition(self):
sample_resource = MakeCounter()
def getResourceCount():
diff --git a/test_all.py b/test_all.py
index c0288bd..e265c90 100755
--- a/test_all.py
+++ b/test_all.py
@@ -54,7 +54,7 @@ class EarlyStoppingTextTestResult(unittest._TextTestResult):
self.stop()
def addFailure(self, test, err):
- unittest._TextTestResult.addError(self, test, err)
+ unittest._TextTestResult.addFailure(self, test, err)
if self.stopOnFailure():
self.stop()