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

Vladimir Iakolev: Functional testing of console apps with Docker

$
0
0

For one of my apps I'd been manually testing some basic functions in a bunch of environments, and it was a huge pain. So I decided to automatize it. As a simplest solution I chose to run an environment in Docker and interact with them through pexpect.

First of all I tried to use docker-py, but it's almost impossible to interact with app run in Docker container, started from docker-py with pexpect. So I just used Docker binary:

fromcontextlibimportcontextmanagerimportsubprocessimportshutilfromtempfileimportmkdtempfrompathlibimportPathimportsysimportpexpect# Absolute path to your source root:root=str(Path(__file__).parent.parent.parent.resolve())def_build_container(tag,dockerfile):"""Creates a temporary folder with Dockerfile, builds an image and    removes the folder."""tmpdir=mkdtemp()withPath(tmpdir).joinpath('Dockerfile').open('w')asfile:file.write(dockerfile)ifsubprocess.call(['docker','build','--tag={}'.format(tag),tmpdir],cwd=root)!=0:raiseException("Can't build a container")shutil.rmtree(tmpdir)@contextmanagerdefspawn(tag,dockerfile,cmd):"""Yields spawn object for `cmd` ran inside a Docker container with an    image build with `tag` and `dockerfile`. Source root is available in `/src`."""_build_container(tag,dockerfile)proc=pexpect.spawnu('docker run --volume {}:/src --tty=true ''--interactive=true {} {}'.format(root,tag,cmd))proc.logfile=sys.stdouttry:yieldprocfinally:proc.terminate()

_build_container is a bit tricky, but it's because Docker binary can build an image only for file named Dockerfile.

This code can be used for running something inside a Docker container very simple, code for printing content of your source root inside the container will be:

withspawn(u'ubuntu-test',u'FROM ubuntu:latest',u'bash')asproc:proc.sendline(u'ls /src')

Back to testing, if we want to test that some application can print version, you can easily write py.test test like this:

container=(u'ubuntu-python',u'''FROM ubuntu:latestRUN apt-get updateRUN apt-get install -yy python''')deftest_version():"""Ensure that app can print current version."""tag,dockerfile=containerwithspawn(tag,dockerfile,u'bash')asproc:proc.sendline(u'cd /src')proc.sendline(u'pip install .')proc.sendline(u'app --version')# Checks that `version:` is in the output:assertproc.expect([pexpect.TIMEOUT,u'version:'])

You can notice the strange assert proc.expect([pexpect.TIMEOUT, u'version:']) construction, it works very simple, if there's version: in output, expect returns 1, if timeout came first - 0.

Also you can notice that all strings are in unicode (u''), it's for compatibility with Python 2. If you use only Python 3, you can remove all u''.

Examples.


Viewing all articles
Browse latest Browse all 22462

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>