Run py.test in a docker container as a service

25,152

Solution 1

I am not exactly sure how your tests execute, but I think I have a similar use case. You can see how I do this in my Envoy project in cmd.sh, and a sample test.

Here is how I run my tests. I'm using pytest as well, but thats not important: 1. use docker-compose to bring up the stack, without the tests 2. wait for the stack to be ready for requests. for me this means poll for a 200 response 3. run the test container separately but make sure it uses the same network as the compose stack.

This can be done in several ways. You can put this all in a Bash script and control it all from your host.

In my case I do this all from a Python container. Its a little to wrap your head around, but the idea is there is a Python test container which the host starts. Then the container itself uses compose to bring up the stack back on the host (dockerception). And then in the test container we run the pytest test. When its done, it composes down the stack and pushes up the return code.

Solution 2

I just enabled it on one of my projects recently. I use a multistage build. At present I put tests in the same folder as the source test_*.py. From my experience with this, it doesn't feel natural, I prefer tests to be in its own folder that is excluded by default.

FROM python:3.7.6 AS build
WORKDIR /app
COPY requirements.txt .
RUN pip3 install --compile -r requirements.txt && rm -rf /root/.cache
COPY src /app
# TODO precompile

# Build stage test - run tests
FROM build AS test
RUN pip3 install pytest pytest-cov && rm -rf /root/.cache
RUN pytest --doctest-modules \
  --junitxml=xunit-reports/xunit-result-all.xml \
  --cov \
  --cov-report=xml:coverage-reports/coverage.xml \
  --cov-report=html:coverage-reports/

# Build stage 3 - Complete the build setting the executable
FROM build AS final
CMD [ "python", "./service.py" ]

In order to exclude the test files from coverage. .coveragerc must be present.

[run]
omit = test_*

The test target runs the required tests and generates coverage and execution reports. These are NOT suitable for Azure DevOps and SonarQube. To make it suitable

sed -i~ 's#/app#$(Build.SourcesDirectory)/app#' $(Pipeline.Workspace)/b/coverage-reports/coverage.xml

To run tests

#!/usr/bin/env bash
set -e
DOCKER_BUILDKIT=1 docker build . --target test --progress plain
Share:
25,152
Kostas Demiris
Author by

Kostas Demiris

Updated on July 09, 2022

Comments

  • Kostas Demiris
    Kostas Demiris almost 2 years

    I am working on setting up a dockerised selenium grid. I can send my python tests [run with pytest] from a pytest container [see below] by attaching to it. But I have setup another LAMP container that is going to control pytest. So I want to make the pytest container standalone,running idle and waiting for commands from the LAMP container.

    I have this Dockerfile:

    # Starting from base image
    FROM ubuntu
    
    #-----------------------------------------------------
    # Set the Github personal token
    ENV GH_TOKEN blablabla
    
    # Install Python & pip
    RUN apt-get update
    RUN apt-get upgrade -y
    RUN apt-get install -y python python-pip python-dev && pip install --upgrade pip
    
    # Install nano for #debugging
    RUN apt-get install -y nano
    
    # Install xvfb
    RUN apt-get install -y xvfb
    
    # Install GIT
    RUN apt-get update -y && apt-get install git -y
    
    # [in the / folder] 
    RUN git clone https://$GH_TOKEN:[email protected]/user/project.git /project
    
    # Install dependencies via pip
    WORKDIR /project
    RUN pip install -r dependencies.txt
    #-----------------------------------------------------
    
    #
    CMD ["/bin/bash"]
    

    I start the pytest container manually [for development] with this:

    docker run -dit -v /project --name pytest repo/user:py
    

    The thing is that I finished development and I want to have the pytest container launched from docker-compose and connect it to other containers [with link and volume]. I just cannot make it to stay up .

    I used this :

    pytest:
      image: repo/user:py
      volumes:
        - "/project"
      command: "/bin/bash tail -f /dev/null"
    

    but didnt work.

    So, inside the Dockerfile, should I use a specific CMD or ENTRYPOINT ?

    Should I use some command from the docker-compose file?

  • Alvin
    Alvin about 3 years
    Brilliant solution, just wish docker build could forward the colour-coding of pytest to the console. Can you also integrate this with Github actions? I'm planning to write the full pipeline and automatize it but I am fairly new to the subject.
  • Archimedes Trajano
    Archimedes Trajano about 3 years
    One of my interview candidates did something to that effect for their job application. Not Python, but still a multistage docker build so I know it is possible.