🧭

Testinfraを使用したDockerコンテナのテスト

2022/09/15に公開

概要

インフラのテストツールであるTestinfraを使用して、Dockerコンテナのテストをしてみました。
docker execしてDockerコンテナにログインし、テストするイメージです。

環境

% python3 --version
Python 3.9.1
% pip list | grep -e ^pytest-testinfra
pytest-testinfra 6.8.0
% docker --version
Docker version 20.10.17, build 100c701

Docker環境の準備

DockerはMacにDocker Desktopをインストールして使用します。
インストール方法は割愛。

テスト用のDockerイメージ取得

Docker Desktopを起動して、Dockerイメージを取得します。

% docker pull docker/getting-started
% docker images
REPOSITORY               TAG       IMAGE ID       CREATED        SIZE
docker/getting-started   latest    cb90f98fd791   5 months ago   28.8MB

DockerコンテナのOSリリース番号取得

Dockerコンテナにログインし、OSのリリース番号を確認します。
この後の工程では、このOSのリリース番号を確認するテストをします。

% docker run -d docker/getting-started
% docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED         STATUS         PORTS     NAMES
416f3f16f8db   docker/getting-started   "/docker-entrypoint.…"   7 seconds ago   Up 6 seconds   80/tcp    interesting_dirac
% docker exec -it 416f3f16f8db /bin/sh
# uname -r
5.10.124-linuxkit
# exit

ホスト側のOSリリース番号はこちら。

% uname -r
21.6.0

Testinfraのインストール

pythonの仮想環境にTestinfraをインストールします。

% python3 -m venv testinfra
% cd testinfra
% source bin/activate
% pip install pytest-testinfra

テスト定義ファイル作成

基本的に公式サイトに掲載されている例のままです。。。
https://testinfra.readthedocs.io/en/latest/examples.html

% mkdir tests
% cd tests
% vi test.py

test.pyの中身はこちら。
ちゃんとDockerコンテナで実行されていれば、test_myimage01が成功し、test_myimage02が失敗します。

test.py
import pytest
import subprocess
import testinfra

@pytest.fixture(scope='session')
def host(request):
  docker_id = subprocess.check_output(['docker', 'run', '-d', 'docker/getting-started']).decode().strip()
  yield testinfra.get_host("docker://" + docker_id)
  subprocess.check_call(['docker', 'rm', '-f', docker_id])

def test_myimage01(host):
  assert host.check_output('uname -r') == '5.10.124-linuxkit'

def test_myimage02(host):
  assert host.check_output('uname -r') == '21.6.0'

Testinfraの実行

DockerコンテナはTestinfra実行時に自動で起動・終了されるので、Docker Desktopが起動していれば実行できます。
失敗したテストは、テスト結果として想定していた内容と実際の内容が出力されます。

% py.test -v test.py
=========================================== test session starts ============================================
platform darwin -- Python 3.9.1, pytest-7.1.3, pluggy-1.0.0 -- /Users/hoge/testinfra/bin/python3
cachedir: .pytest_cache
rootdir: /Users/hoge/testinfra/tests
plugins: testinfra-6.8.0
collected 2 items

test.py::test_myimage01 PASSED                                                                       [ 50%]
test.py::test_myimage02 FAILED                                                                       [100%]

================================================= FAILURES =================================================
______________________________________________ test_myimage02 ______________________________________________

host = <testinfra.host.Host docker://9939579997d7c570444f27d3ed42e8f3944c53e0a7fc525385e4b377b50a93c3>

    def test_myimage02(host):
>     assert host.check_output('uname -r') == '21.6.0'
E     AssertionError: assert '5.10.124-linuxkit' == '21.6.0'
E       - 21.6.0
E       + 5.10.124-linuxkit

test.py:15: AssertionError
----------------------------------------- Captured stdout teardown -----------------------------------------
9939579997d7c570444f27d3ed42e8f3944c53e0a7fc525385e4b377b50a93c3
========================================= short test summary info ==========================================
FAILED test.py::test_myimage02 - AssertionError: assert '5.10.124-linuxkit' == '21.6.0'
======================================= 1 failed, 1 passed in 1.75s ========================================

JUnit形式での出力

JUnit形式のXMLを出力することもできます。

% mkdir ../reports
% py.test --junit-xml=../reports/test_report.xml test.py
=========================================== test session starts ============================================
platform darwin -- Python 3.9.1, pytest-7.1.3, pluggy-1.0.0
rootdir: /Users/hoge/testinfra/tests
plugins: testinfra-6.8.0
collected 2 items

test.py .F                                                                                           [100%]

================================================= FAILURES =================================================
______________________________________________ test_myimage02 ______________________________________________

host = <testinfra.host.Host docker://cbc7c2431ad7fe545ae553c81907954f3954f1c208f4e7136195d31696b7d607>

    def test_myimage02(host):
>     assert host.check_output('uname -r') == '21.6.0'
E     AssertionError: assert '5.10.124-linuxkit' == '21.6.0'
E       - 21.6.0
E       + 5.10.124-linuxkit

test.py:15: AssertionError
----------------------------------------- Captured stdout teardown -----------------------------------------
cbc7c2431ad7fe545ae553c81907954f3954f1c208f4e7136195d31696b7d607
--------------------- generated xml file: /Users/hoge/testinfra/reports/test_report.xml ---------------------
========================================= short test summary info ==========================================
FAILED test.py::test_myimage02 - AssertionError: assert '5.10.124-linuxkit' == '21.6.0'
======================================= 1 failed, 1 passed in 1.77s ========================================

% file ../reports/test_report.xml
../reports/test_report.xml: XML 1.0 document text, ASCII text, with very long lines (567)

Discussion