Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22847

Vladimir Iakolev: py.test plugin for functional testing with Docker

$
0
0

It's very useful to run functional tests in a clean environment, like a fresh Docker container, and I wrote about this before, and now it was formalized in a simple py.test plugin — pytest-docker-pexpect.

It provides few useful fixtures:

  • spawnupexpect.spawnu object attached to a container, it can be used to interact with apps inside the container, read more;
  • TIMEOUT– a special object, that can be used in assertions those checks output;
  • run_without_docker– indicates that tests running without Docker, when py.test called with --run-without-docker.

And some marks:

  • skip_without_docker– skips test when without Docker;
  • once_without_docker– runs parametrized test only with a first set of params when without Docker.

It's easier to show it in examples. So, first of all, just test some app --version argument inside an Ubuntu container:

importpytest@pytest.fixturedefubuntu(spawnu):# Get `spawnu` attached to ubuntu container with installed python and# where bash ranproc=spawnu(u'example/ubuntu',u'''FROM ubuntu:latest                      RUN apt-get update                      RUN apt-get install python python-dev python-pip''',u'bash')# Sources root is available in `/src`proc.sendline(u'pip install /src')returnprocdeftest_version(ubuntu,TIMEOUT):ubuntu.sendline(u'app --version')# Asserts that `The App 2.9.1` came before timeout,# when timeout came first, `expect` returns 0, when app version - 1assertubuntu.expect([TIMEOUT,u'The App 2.9.1'])

Looks simple. But sometimes we need to run tests in different environments, for example — with different Python versions. It can be easily done by just changing ubuntu fixture:

@pytest.fixture(params=[2,3])defubuntu(request,spawnu):python_version=request.param# Get `spawnu` attached to ubuntu container with installed python and# where bash randockerfile=u'''        FROM ubuntu:latest        RUN apt-get update        RUN apt-get install python{version} python{version}-dev python{version}-pip    '''.format(version=python_version)proc=spawnu(u'example/ubuntu',dockerfile,u'bash')# Your source root is available in `/src`proc.sendline(u'pip{} install /src'.format(python_version))returnproc

And sometimes we need to run tests in Docker-less environment, for example — in Travis CI container-based infrastructure. So here's where --run-without-docker argument comes handy. But we don't need to run tests for more than one environment in a single Travis CI run, and we don't need to make some installation steps. So there's place for once_without_docker mark and run_without_docker fixture, test with them will be:

importpytest@pytest.fixture(params=[2,3])defubuntu(request,spawnu,run_without_docker):python_version=request.param# Get `spawnu` attached to ubuntu container with installed python and# where bash randockerfile=u'''        FROM ubuntu:latest        RUN apt-get update        RUN apt-get install python{version} python{version}-dev python{version}-pip    '''.format(version=python_version)proc=spawnu(u'example/ubuntu',dockerfile,u'bash')# It's already installed if we run without Docker:ifnotrun_without_docker:# Your source root is available in `/src`proc.sendline(u'pip{} install /src'.format(python_version))returnproc@pytest.mark.once_without_dockerdeftest_version(ubuntu,TIMEOUT):ubuntu.sendline(u'app --version')# Asserts that `The App 2.9.1` came before timeout,# when timeout came first, `expect` returns 0, when app version - 1assertubuntu.expect([TIMEOUT,u'The App 2.9.1'])

Another often requirement — skip some tests without docker, some destructive tests. It can be done with skip_without_docker mark:

@pytest.mark.skip_without_dockerdeftest_broke_config(ubuntu,TIMEOUT):ubuntu.sendline(u'{invalid} > ~/.app/config.json')ubuntu.sendline(u'app')assertubuntu.expect([TIMEOUT,u'Config was broken!'])

Source code of the plugin.


Viewing all articles
Browse latest Browse all 22847

Trending Articles