Testing the container
We will start by creating a service to run the unit tests. Keep in mind that the tests need to run inside the container. This will standardize the execution of them and ensure that the dependencies are constant.
This certainly creates a smaller running container but creates a situation where the testing container is not 100% exactly the same as the one in production. If the size is critical and there's a big difference, this may be an option, but be aware of the differentiation if there's a subtle bug.
We need to define a service in the docker-compose.yaml file, in this way:
version: '3.7'
services:
# Development related
test-sqlite:
environment:
- PYTHONDONTWRITEBYTECODE=1
build:
dockerfile: docker/app/Dockerfile
context: .
entrypoint: pytest
volumes:
- ./ThoughtsBackend:/opt/code
This section defines a service called test-sqlite. The build defines the Dockerfile to use and the context, in the same way as we'd do with a docker build command. docker-compose automatically sets the name.
We can build the container with the following command:
$ docker-compose build test-sqlite
Building test-sqlite
...
Successfully built 8751a4a870d9
Successfully tagged ch3_test-sqlite:latest
entrypoint specifies the command to run, in this case, running the tests through the pytest command.
To run the container, call the run command:
$ docker-compose run test-sqlite
=================== test session starts ===================
platform linux -- Python 3.6.8, pytest-4.5.0, py-1.8.0, pluggy-0.12.0 -- /opt/venv/bin/python3
cachedir: .pytest_cache
rootdir: /opt/code, inifile: pytest.ini
plugins: flask-0.14.0
collected 17 items
tests/test_thoughts.py::test_create_me_thought PASSED [ 5%]
...
tests/test_token_validation.py::test_valid_token_header PASSED [100%]
========== 17 passed, 177 warnings in 1.25 seconds ============
$
You can append pytest arguments that will be passed over to the internal entrypoint. For example, to run tests that match the validation string, run the following command:
$ docker-compose run test-sqlite -k validation
...
===== 9 passed, 8 deselected, 13 warnings in 0.30 seconds =======
$
There are two extra details: the current code is mounted through a volume and overwrites the code in the container. See how the current code in ./ThoughtsBackend is mounted in the position of the code in the container, /opt/code. This is very handy for the development, as it will avoid having to rebuild the container each time a change is made.
This also means that any write in the mounted directory hierarchy will be saved in your local filesystem. For example, the ./ThoughtsBackend/db.sqlite3 database file allows you to use it for testing. It will also store generated pyc files.
That's why we use the environment option to pass a PYTHONDONTWRITEBYTECODE=1 environment variable. This stops Python from creating pyc files.
While SQLite is good for testing, we need to create a better structure reflective of the deployment and to configure the access to the database to be able to deploy the server.