Test framework integration¶
We have strong opinions about the testing tools we use, and we understand that other people may have equally strong opinions that differ from ours. For this reason, we have decided that none of Seaworthy’s core functionality will depend on pytest, testtools, or anything else that might get in the way of how people might wants to write their tests. On the other hand, we don’t want to reinvent a bunch of integration and helper code for all the third-party testing tools we like, so we also provide optional integration modules where it makes sense to do so.
pytest¶
Seaworthy is a pytest plugin and all the functions and fixtures in the
seaworthy.pytest
module will be available when Seaworthy is used with
pytest.
docker_helper
fixture¶
A fixture for a DockerHelper
instance is defined by
default.
This fixture creates DockerHelper
instances with default parameters and has
module-level scope. Since all other Docker resource fixtures typically
depend on the docker_helper
fixture, resources must have a scope smaller
than or equal to the docker_helper
’s scope.
The defaults for this fixture can be overridden by defining a new
docker_helper
fixture using the
docker_helper_fixture()
fixture factory. For
example:
from seaworthy.pytest.fixtures import docker_helper_fixture
docker_helper = docker_helper_fixture(scope='session', namespace='seaworthy')
…would change the scope of the docker_helper
fixture to the session-level
and change the namespace of created Docker resources to seaworthy
.
dockertest
decorator¶
The dockertest()
decorator can be used to mark
tests that require Docker to run. These tests will be skipped if Docker is
not available. It’s possible that some tests in your test suite may not require
Docker and you may want to still be able to run your tests in an environment
that does not have Docker available. The decorator can be used as follows:
@dockertest()
def test_docker_thing(cake_container):
assert cake_container.exec_cake('variant') == ['gateau']
Fixture factories¶
A few functions are provided in the seaworthy.pytest.fixtures
module
that are factories for fixtures. The most important two are:
-
resource_fixture
(definition, name, scope='function', dependencies=())[source] Create a fixture for a resource.
Note
This function returns a fixture function. It is important to keep a reference to the returned function within the scope of the tests that use the fixture.
fixture = resource_fixture(PostgreSQLContainer(), 'postgresql') def test_container(postgresql): """Test something about the PostgreSQL container..."""
Parameters: - definition – A resource definition, one of those defined in the
seaworthy.definitions
module. - name – The fixture name.
- scope – The scope of the fixture.
- dependencies – A sequence of names of other pytest fixtures that this fixture depends on. These fixtures will be requested from pytest and so will be setup, but nothing is done with the actual fixture values.
Returns: The fixture function.
- definition – A resource definition, one of those defined in the
-
clean_container_fixtures
(container, name, scope='class', dependencies=())[source] Creates a fixture for a container that can be “cleaned”. When a code block is marked with
@pytest.mark.clean_<fixture name>
then theclean
method will be called on the container object before it is passed as an argument to the test function.Note
This function returns two fixture functions. It is important to keep references to the returned functions within the scope of the tests that use the fixtures.
f1, f2 = clean_container_fixtures(PostgreSQLContainer(), 'postgresql') class TestPostgresqlContainer @pytest.mark.clean_postgresql def test_clean_container(self, web_container, postgresql): """ Test something about the container that requires it to have a clean state (e.g. database table creation). """ def test_dirty_container(self, web_container, postgresql): """ Test something about the container that doesn't require it to have a clean state (e.g. testing something about a dependent container). """
Parameters: - container – A “container” object that is a subclass of
ContainerDefinition
. - name – The fixture name.
- scope – The scope of the fixture.
- dependencies – A sequence of names of other pytest fixtures that this fixture depends on. These fixtures will be requested from pytest and so will be setup, but nothing is done with the actual fixture values.
Returns: A tuple of two fixture functions.
- container – A “container” object that is a subclass of
testtools¶
We primarily use testtools when matching against complex data structures and
don’t use any of its test runner functionality. Currently, testtools matchers
are only used for matching PsTree
objects. See the API
documentation for the seaworthy.ps
module.
Testing our integrations¶
To make sure that none of the optional dependencies accidentally creep into the core modules (or other optional modules), we have several sets of tests that run in different environments:
tests-core
: This is a set of core tests that cover basic functionality.tox -e py36-core
will run just these tests in an environment without any optional or extra dependencies installed.tests-pytest
, etc.: These are tests for the optional pytest integration modules.tox -e py36-testtools
will run just theseaworthy.pytest
modules’ tests in an environment with only the necessary dependencies installed.tests-testtools
, etc.: These are tests for the optional testtools integration module.tox -e py36-testtools
will run just theseaworthy.testtools
module’s tests.tests
: These are general tests that are hard or annoying to write with only the minimal dependencies, so we don’t have any tooling restrictions here.tox -e py36-full
will run these, as well as all the other test sets mentioned above, in an environment with all optional dependencies (and potentially some additional test-only dependencies) installed.