|
11 | 11 |
|
12 | 12 | Here is a minimal example demonstrating how to use testresources in your |
13 | 13 | project. It's not very useful - temporary directories are *not* the kind of |
14 | | -resource that testresources are most useful for - but it does demonstrate some |
15 | | -of the key concepts and classes, which we will discuss in more detail below. |
16 | | -Firstly, we have our "resource manager": |
| 14 | +resource that testresources are most useful for and you would be better off |
| 15 | +using something like fixtures for this - but it does demonstrate some of the |
| 16 | +key concepts and classes, which we will discuss in more detail below. Firstly, |
| 17 | +we have our "resource manager": |
17 | 18 |
|
18 | 19 | .. code-block:: python |
19 | 20 |
|
@@ -204,12 +205,16 @@ See pydoc testresources.TestResourceManager for details. |
204 | 205 |
|
205 | 206 | Glue to adapt testresources to an existing resource-like class. |
206 | 207 |
|
| 208 | +.. _fixtureresource: |
| 209 | + |
207 | 210 | ``testresources.FixtureResource`` |
208 | 211 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
209 | 212 |
|
210 | | -Glue to adapt testresources to the simpler fixtures.Fixture API. Long |
211 | | -term testresources is likely to consolidate on that simpler API as the |
212 | | -recommended method of writing resources. |
| 213 | +Glue to adapt testresources to the simpler ``fixtures.Fixture`` API. Long term |
| 214 | +testresources is likely to consolidate on that simpler API as the recommended |
| 215 | +method of writing resources. |
| 216 | + |
| 217 | +This is discussed in further detail in `testresources vs. fixtures`_. |
213 | 218 |
|
214 | 219 | ``testresources.OptimisingTestSuite`` |
215 | 220 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
@@ -264,6 +269,53 @@ see if it is safe to reuse. |
264 | 269 | Finally, you can arrange for the returned resource to always call back to |
265 | 270 | ``TestResourceManager.dirtied`` on the first operation that mutates it. |
266 | 271 |
|
| 272 | +testresources vs. fixtures |
| 273 | +-------------------------- |
| 274 | + |
| 275 | +The `fixtures <https://pypi.org/project/fixtures/>`_ library solves a similar |
| 276 | +problem: managing test dependencies that need to be set up and torn down. |
| 277 | +However, testresources and fixtures differ in the scope of the test |
| 278 | +dependencies they manage. |
| 279 | + |
| 280 | +testresources is designed for resources that are expensive to create and can be |
| 281 | +safely shared across multiple tests. The ``OptimisingTestSuite`` reorders |
| 282 | +tests at the suite level so that tests sharing the same expensive resource run |
| 283 | +consecutively, minimising the total number of setup and teardown cycles. This |
| 284 | +makes sense when the cost of constructing the resource is meaningfully large |
| 285 | +relative to the cost of running the tests themselves. Examples of areas where |
| 286 | +testresources makes sense would be provisioning database backends that are |
| 287 | +shared across tests, or loading large, static test assets from disk. |
| 288 | + |
| 289 | +By comparison, fixtures is designed for per-test setup and teardown. A fixture |
| 290 | +is created fresh (or at least reset) for each test, and tests interact with it |
| 291 | +via ``useFixture()``. fixtures is therefore far better suited for things like |
| 292 | +mock patches, temporary directories, fake loggers, environment variables, or |
| 293 | +fake HTTP sessions. In all these cases, the overhead of managing the resources |
| 294 | +is low enough that recreating them per test is perfectly acceptable. |
| 295 | + |
| 296 | +Finally, there may be cases where you wish to use the framework provided by |
| 297 | +``fixtures.Fixture`` but avoid recreating it for every test in a module. To |
| 298 | +this end, the ``FixtureResource`` class is what you want. As discussed |
| 299 | +`previously <fixtureresource>`, this is a glue class that wraps any |
| 300 | +``fixtures.Fixture`` so it can participate in testresources' suite-level |
| 301 | +optimisation. If you already have a well-written fixture but want to avoid |
| 302 | +recreating it for every test in a module, wrapping it in a ``FixtureResource`` |
| 303 | +and adding the ``load_tests`` hook is all that is needed. For example: |
| 304 | + |
| 305 | +.. code-block:: python |
| 306 | +
|
| 307 | + # Defined once at module scope so that all tests share the same instance. |
| 308 | + MY_RESOURCE = testresources.FixtureResource(MyExpensiveFixture()) |
| 309 | +
|
| 310 | + class MyTest(unittest.TestCase, testresources.ResourcedTestCase): |
| 311 | + resources = [('data', MY_RESOURCE)] |
| 312 | +
|
| 313 | + def test_something(self): |
| 314 | + self.data.some_attribute # provided by MyExpensiveFixture |
| 315 | +
|
| 316 | + def load_tests(loader, tests, pattern): |
| 317 | + return testresources.OptimisingTestSuite(tests) |
| 318 | +
|
267 | 319 | FAQ |
268 | 320 | --- |
269 | 321 |
|
|
0 commit comments