From c777c64881eb7ea82549e13b21452ab1b82c39bc Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 6 Mar 2026 10:28:04 +0000 Subject: [PATCH 1/3] Restructure README Place the license and build instructions at the end, rather than at the start, and begin instead with an introduction into why you would use this library. Also change the header levels to something more usual and drop the release instructions which were clearly outdated. Signed-off-by: Stephen Finucane --- README.rst | 101 ++++++++++++++++++++--------------------------------- 1 file changed, 38 insertions(+), 63 deletions(-) diff --git a/README.rst b/README.rst index a8afa71..8046b1e 100644 --- a/README.rst +++ b/README.rst @@ -1,48 +1,13 @@ -testresources: extensions to python unittest to allow declarative use -of resources by test cases. +testresources +============= -Copyright (C) 2005-2013 Robert Collins - - Licensed under either the Apache License, Version 2.0 or the BSD 3-clause - license at the users choice. A copy of both licenses are available in the - project source as Apache-2.0 and BSD. You may not use this file except in - compliance with one of these two licences. - - Unless required by applicable law or agreed to in writing, software - distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT - WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - license you chose for the specific language governing permissions and - limitations under that license. - - See the COPYING file for full details on the licensing of Testresources. - - -Testresources -+++++++++++++ - -testresources extends unittest with a clean and simple api to provide test +testresources extends ``unittest`` with a clean and simple API to provide test optimisation where expensive common resources are needed for test cases - for example sample working trees for VCS systems, reference databases for -enterprise applications, or web servers ... let imagination run wild. - -Dependencies to build/selftest -============================== - -* Python 3.9+ -* docutils -* testtools (http://pypi.python.org/pypi/testtools/) -* fixtures (http://pypi.python.org/pypi/fixtures) - -Dependencies to use testresources -================================= - -* Python 3.9+ - -For older versions of Python, testresources <= 1.0.0 supported 2.4, 2.5 and -3.2. +enterprise applications, or web servers ... let your imagination run wild. How testresources Works -======================= +----------------------- The basic idea of testresources is: @@ -65,10 +30,10 @@ features, the result will be flattened for optimisation and those setup's will not run at all. Main Classes -============ +------------ -testresources.ResourcedTestCase -------------------------------- +``testresources.ResourcedTestCase`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By extending or mixing-in this class, tests can have necessary resources automatically allocated and disposed or recycled. @@ -99,8 +64,8 @@ For example:: def test_log(self): show_log(self.branch, ...) -testresources.TestResourceManager ---------------------------------- +``testresources.TestResourceManager`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A TestResourceManager is an object that tests can use to create resources. It can be overridden to manage different types of resources. Normally test code @@ -175,20 +140,20 @@ See pydoc testresources.TestResourceManager for details. .. _sample: doc/example.py -testresources.GenericResource ------------------------------ +``testresources.GenericResource`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Glue to adapt testresources to an existing resource-like class. -testresources.FixtureResource ------------------------------ +``testresources.FixtureResource`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Glue to adapt testresources to the simpler fixtures.Fixture API. Long term testresources is likely to consolidate on that simpler API as the recommended method of writing resources. -testresources.OptimisingTestSuite ---------------------------------- +``testresources.OptimisingTestSuite`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This TestSuite will introspect all the test cases it holds directly and if they declare needed resources, will run the tests in an order that attempts to @@ -208,14 +173,13 @@ OptimisingTestSuite. You could add everything to a single OptimisingTestSuite, getting global optimisation or you could use several smaller OptimisingTestSuites. - -testresources.TestLoader ------------------------- +``testresources.TestLoader`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is a trivial TestLoader that creates OptimisingTestSuites by default. -unittest.TestResult -------------------- +``unittest.TestResult`` +~~~~~~~~~~~~~~~~~~~~~~~ testresources will log activity about resource creation and destruction to the result object tests are run with. 6 extension methods are looked for: @@ -225,7 +189,7 @@ result object tests are run with. 6 extension methods are looked for: an example of a ``TestResult`` with these methods present. Controlling Resource Reuse -========================== +-------------------------- When or how do I mark the resource dirtied? @@ -242,7 +206,7 @@ Finally, you can arrange for the returned resource to always call back to ``TestResourceManager.dirtied`` on the first operation that mutates it. FAQ -=== +--- * Can I dynamically request resources inside a test method? @@ -264,9 +228,20 @@ FAQ I guess you should arrange for a single instance to be held in an appropriate module scope, then referenced by the test classes that want to share it. -Releasing -========= +License +------- + +Copyright (C) 2005-2013 Robert Collins + + Licensed under either the Apache License, Version 2.0 or the BSD 3-clause + license at the users choice. A copy of both licenses are available in the + project source as Apache-2.0 and BSD. You may not use this file except in + compliance with one of these two licences. + + Unless required by applicable law or agreed to in writing, software + distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + license you chose for the specific language governing permissions and + limitations under that license. -1. Add a section to NEWS (after In Development). -2. git tag -s -3. python setup.py sdist bdist_wheel upload -s + See the COPYING file for full details on the licensing of Testresources. From 42a675e7a7733f7169cf461a9bc7b9c3cf0a8387 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 6 Mar 2026 10:45:48 +0000 Subject: [PATCH 2/3] README: Add usage example Get people started with testscenarios nice and quickly. Signed-off-by: Stephen Finucane --- README.rst | 73 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 8046b1e..8984166 100644 --- a/README.rst +++ b/README.rst @@ -6,14 +6,73 @@ optimisation where expensive common resources are needed for test cases - for example sample working trees for VCS systems, reference databases for enterprise applications, or web servers ... let your imagination run wild. -How testresources Works ------------------------ +Usage +----- + +Here is a minimal example demonstrating how to use testresources in your +project. It's not very useful - temporary directories are *not* the kind of +resource that testresources are most useful for - but it does demonstrate some +of the key concepts and classes, which we will discuss in more detail below. +Firstly, we have our "resource manager": + +.. code-block:: python + + import shutil + import tempfile + import testresources + + + class TemporaryDirectoryResource(testresources.TestResourceManager): + + def make(self, dependency_resources): + return tempfile.mkdtemp() + + def clean(self, resource): + shutil.rmtree(resource) + + def isDirty(self, resource): + # Assume the directory is always modified after use. + return True + +With the resource manager in place, we can then declare the resource in a test +and access it via the assigned attribute: + +.. code-block:: python + + import os + import unittest + + + class TestMyCode(unittest.TestCase, testresources.ResourcedTestCase): + + resources = [('workdir', TemporaryDirectoryResource())] + + def test_create_file(self): + # self.workdir is automatically set up before this test runs + # and torn down (or reused) afterwards. + path = os.path.join(self.workdir, 'output.txt') + with open(path, 'w') as f: + f.write('hello') + self.assertTrue(os.path.exists(path)) + +Finally, we need to add a ``load_tests`` hook to the test module so that we cna +use the ``OptimisingTestSuite``. This ensures our test runner will reorder +tests to minimise the number of times the resource is set up and torn down: + +.. code-block:: python + + def load_tests(loader, tests, pattern): + return testresources.OptimisingTestSuite(tests) + +How it works +------------ The basic idea of testresources is: * Tests declare the resources they need in a ``resources`` attribute. * When the test is run, the required resource objects are allocated (either - newly constructed, or reused), and assigned to attributes of the TestCase. + newly constructed, or reused), and assigned to attributes of the + ``TestCase``. testresources distinguishes a 'resource manager' (a subclass of ``TestResourceManager``) which acts as a kind of factory, and a 'resource' @@ -29,7 +88,7 @@ when an OptimisingTestSuite is wrapped around a test suite using those features, the result will be flattened for optimisation and those setup's will not run at all. -Main Classes +Main classes ------------ ``testresources.ResourcedTestCase`` @@ -185,10 +244,10 @@ testresources will log activity about resource creation and destruction to the result object tests are run with. 6 extension methods are looked for: ``startCleanResource``, ``stopCleanResource``, ``startMakeResource``, ``stopMakeResource``, ``startResetResource`` and finally ``stopResetResource``. -``testresources.tests.ResultWithResourceExtensions`` is -an example of a ``TestResult`` with these methods present. +``testresources.tests.ResultWithResourceExtensions`` is an example of a +``TestResult`` with these methods present. -Controlling Resource Reuse +Controlling resource reuse -------------------------- When or how do I mark the resource dirtied? From 537500c51e1aed611776c48c96b593443ff43278 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 6 Mar 2026 10:49:22 +0000 Subject: [PATCH 3/3] README: Add comparison with fixtures Signed-off-by: Stephen Finucane --- README.rst | 64 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 8984166..d731418 100644 --- a/README.rst +++ b/README.rst @@ -11,9 +11,10 @@ Usage Here is a minimal example demonstrating how to use testresources in your project. It's not very useful - temporary directories are *not* the kind of -resource that testresources are most useful for - but it does demonstrate some -of the key concepts and classes, which we will discuss in more detail below. -Firstly, we have our "resource manager": +resource that testresources are most useful for and you would be better off +using something like fixtures for this - but it does demonstrate some of the +key concepts and classes, which we will discuss in more detail below. Firstly, +we have our "resource manager": .. code-block:: python @@ -204,12 +205,16 @@ See pydoc testresources.TestResourceManager for details. Glue to adapt testresources to an existing resource-like class. +.. _fixtureresource: + ``testresources.FixtureResource`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Glue to adapt testresources to the simpler fixtures.Fixture API. Long -term testresources is likely to consolidate on that simpler API as the -recommended method of writing resources. +Glue to adapt testresources to the simpler ``fixtures.Fixture`` API. Long term +testresources is likely to consolidate on that simpler API as the recommended +method of writing resources. + +This is discussed in further detail in `testresources vs. fixtures`_. ``testresources.OptimisingTestSuite`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -264,6 +269,53 @@ see if it is safe to reuse. Finally, you can arrange for the returned resource to always call back to ``TestResourceManager.dirtied`` on the first operation that mutates it. +testresources vs. fixtures +-------------------------- + +The `fixtures `_ library solves a similar +problem: managing test dependencies that need to be set up and torn down. +However, testresources and fixtures differ in the scope of the test +dependencies they manage. + +testresources is designed for resources that are expensive to create and can be +safely shared across multiple tests. The ``OptimisingTestSuite`` reorders +tests at the suite level so that tests sharing the same expensive resource run +consecutively, minimising the total number of setup and teardown cycles. This +makes sense when the cost of constructing the resource is meaningfully large +relative to the cost of running the tests themselves. Examples of areas where +testresources makes sense would be provisioning database backends that are +shared across tests, or loading large, static test assets from disk. + +By comparison, fixtures is designed for per-test setup and teardown. A fixture +is created fresh (or at least reset) for each test, and tests interact with it +via ``useFixture()``. fixtures is therefore far better suited for things like +mock patches, temporary directories, fake loggers, environment variables, or +fake HTTP sessions. In all these cases, the overhead of managing the resources +is low enough that recreating them per test is perfectly acceptable. + +Finally, there may be cases where you wish to use the framework provided by +``fixtures.Fixture`` but avoid recreating it for every test in a module. To +this end, the ``FixtureResource`` class is what you want. As discussed +`previously `, this is a glue class that wraps any +``fixtures.Fixture`` so it can participate in testresources' suite-level +optimisation. If you already have a well-written fixture but want to avoid +recreating it for every test in a module, wrapping it in a ``FixtureResource`` +and adding the ``load_tests`` hook is all that is needed. For example: + +.. code-block:: python + + # Defined once at module scope so that all tests share the same instance. + MY_RESOURCE = testresources.FixtureResource(MyExpensiveFixture()) + + class MyTest(unittest.TestCase, testresources.ResourcedTestCase): + resources = [('data', MY_RESOURCE)] + + def test_something(self): + self.data.some_attribute # provided by MyExpensiveFixture + + def load_tests(loader, tests, pattern): + return testresources.OptimisingTestSuite(tests) + FAQ ---