Юнит-тесты для образов Docker | OTUS

Юнит-тесты для образов Docker

Тес­тирова­ние — важ­ный шаг на всех эта­пах раз­работ­ки ПО. Но не все ком­понен­ты име­ют оче­вид­ные, извес­тные и понят­ные пути тес­тирова­ния. К при­меру, обра­зы Docker либо не тес­тиру­ют вооб­ще, либо тес­тиру­ют толь­ко на при­год­ность к запус­ку. Как про­тес­тировать образ Docker так, что­бы убе­дить­ся в том, что он выпол­няет свои задачи?

Юнит‑тес­тирова­ние (или модуль­ное тес­тирова­ние) — это про­цесс в раз­работ­ке прог­рам­мно­го обес­печения, поз­воля­ющий про­верить работос­пособ­ность отдель­ных модулей исходно­го кода. Такое тес­тирова­ние при­выч­но при­меня­ется в раз­работ­ке непос­редс­твен­но прог­рам­мно­го обес­печения, одна­ко с ходу слож­но себе пред­ста­вить юнит‑тес­тирова­ние обра­за Docker.

Взгля­нем на прос­тей­ший Dockerfile:

FROM busybox:1.32.1
RUN echo 'Hello, World!' > /test.txt

Здесь мы выпол­няем единс­твен­ное дей­ствие — добав­ляем файл со стро­кой Hello, World! в файл /test.txt.

Как мож­но про­верить, что мы дос­тига­ем жела­емо­го резуль­тата? Мож­но запус­тить соб­ранный кон­тей­нер и пос­мотреть, что, во‑пер­вых, нуж­ный файл при­сутс­тву­ет, а во‑вто­рых, его содер­жимое рав­но ожи­даемо­му.

$ docker build -t test .
[+] Building 7.7s (6/6) FINISHED
$ docker run --rm test ls -lha /test.txt
-rw-r--r--    1 root     root          14 Feb 20 19:26 /test.txt
$ docker run --rm test cat /test.txt
Hello, World!

Не слиш­ком удоб­но, не так ли? К счастью, сущес­тву­ет фрей­мворк terratest. Он поз­воля­ет писать тес­ты на Golang для Docker (и docker-compose) так же, как и для обыч­ного кода!

Взгля­нем на прог­рам­мную реали­зацию дан­ного тес­та:

package docker_test
import (
    "testing"
    "github.com/gruntwork-io/terratest/modules/docker"
    "github.com/stretchr/testify/assert"
)
func TestDockerImage(t *testing.T) {
    // Определяем название образа для тестирования
    tag := "test"
    buildOptions := &docker.BuildOptions{
        Tags: []string{tag},
    }
    // Собираем образ из Dockerfile’а
    docker.Build(t, "../", buildOptions)
    // Фактически выставляем как опции запуск контейнера со следующими командами
    // Команда, которая вернет 'exists', если файл существует
    eOpts := &docker.RunOptions{Command: []string{"sh", "-c", "[ -f /test.txt ] && echo exists"}}
    // Команда, которая вернет содержимое файла
    cOpts := &docker.RunOptions{Command: []string{"cat", "/test.txt"}}
    // Запускаем контейнер с проверкой на наличие файла
    chkExisting := docker.Run(t, tag, eOpts)
    // Проверяем, что вывод равен желаемому
    assert.Equal(t, "exists", chkExisting)
    // Запускаем контейнер с выводом содержимого файла
    chkContent := docker.Run(t, tag, cOpts)
    // Проверяем, что вывод равен желаемому
    assert.Equal(t, "Hello, World!", chkContent)
}

Ста­ло ощу­тимо удоб­нее! Бла­года­ря пол­ноцен­ному язы­ку прог­рамми­рова­ния мы можем соз­давать нам­ного более слож­ные сце­нарии тес­тирова­ния, исполь­зовать API докер и так далее.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться