🤖

Selenium×dockerでテスト自動化してみた

2023/06/27に公開

はじめに

はじめまして。shibuです。
本記事では「Selenium×dockerでテスト自動化してみた」ということで、Seleniumを使ってテストを自動化する方法を紹介します。これからテスト自動化に挑戦してみようと思っている方の参考になればと思います。

背景

ミドルウェアがアップデートされるタイミングなどでWEBサイトの動作検証を行っていましたが、頻度が多く、地味に時間も掛かっているということでテスト自動化の検討を始めました。

検討する中で他にも自動化ツールがありましたが、情報量の多さ、使いやすさから「Selenium」を使うことにしました。また、テストを行う上で、環境を汚したくないという思いから「docker」を使うことにしました。

やったこと

Seleniumを使う上で必要な環境の準備とテストプログラムの作成と実行を行いました。テストプログラムはWEBサイトにログイン、検索などの操作を行い、各画面のキャプチャを保存するというものです。

構成

テストプログラム等のの配置は以下となります。
また、Red Hat系のディストリビューション(CentOSやRocky Linux)で動かすことを前提としています。

Automatedtest/
	├app
	│ ├ temp
	│ ├ publicTest.py
	│ └ BaseClass.py
	└ dockerfile

dockerのインストール

まず最初に、Dockerをインストールします。

	sudo yum -y install device-mapper-persistent-data lvm2
	sudo yum config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
	sudo yum -y install docker-ce
	sudo systemctl start docker
	sudo systemctl enable docker

テストプログラムの作成

自動化させたいテストプログラムを作成します。ここではPythonで書いていますが、JavaScript、C#など他の言語でも書くことができます。
プログラムは2つ用意しています。BaseClass.pyは共通処理をまとめたもの、publicTest.pyは実行するテストプログラムです。

BaseClass.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import os
import shutil
import configparser

class BaseClass():
    def __init__(self,folder):
        # 初期設定
        service = Service(executable_path=r'/usr/bin/chromedriver')
        options = webdriver.ChromeOptions()
        options.add_argument('--headless')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        options.add_argument('--disable-gpu')
        options.add_argument('--window-size=1200x1800')
        prefs = {"download.default_directory" : folder}
        options.add_experimental_option("prefs",prefs)
        self.driver = webdriver.Chrome(service=service, options=options)
        self.target_dir = folder

        # 画像保存用のディレクトリを用意
        if not os.path.isdir(folder):
            os.makedirs(folder)
        else:
            shutil.rmtree(folder)
            os.mkdir(folder)
            
    # チェック&スクリーンショット
    def checkAndScreenshot(self,num):
        if 'Notice:' in self.driver.page_source:
            print('HTMLの中に「Notice:」の文字列が見つかりました。')
        if 'Warning:' in self.driver.page_source:
            print('HTMLの中に「Warning:」の文字列が見つかりました。')
        if 'Fatal error' in self.driver.page_source:
            print('HTMLの中に「Fatal error」の文字列が見つかりました。')
        self.driver.save_screenshot(str(self.target_dir) + '/' + str(num) + '.png')
publicTest.py
import BaseClass as base

try:
    # 画像保存用のディレクトリパス
    target_dir = 'temp/publicTest'

    # --------------------------------------------------------------------
    # テストシナリオ
    # 公開サイトのログイン ⇒ 検索 ⇒ ログアウト
    # --------------------------------------------------------------------

    # サイトアクセス
    my = base.BaseClass(target_dir)
    my.driver.get('https://・・・・・')
    
    # ログイン
    my.checkAndScreenshot(0)
    my.driver.find_element_by_xpath(u"//a[contains(text(),'ログイン')]").click()
    my.checkAndScreenshot(1)
    my.driver.find_element_by_name("login_id").send_keys('id')
    my.driver.find_element_by_name("password").send_keys('password')
    my.driver.find_element_by_xpath(u"//input[@value='ログイン']") .click()
    my.checkAndScreenshot(2)

    # 検索
    my.driver.find_element_by_name("search").click()
    my.checkAndScreenshot(3)

    # ログアウト
    my.driver.find_element_by_link_text(u"ログアウト").click()
    my.checkAndScreenshot(4)

    my.driver.quit()

except Exception as e:
    print(e)

Dockerfileの作成

ソフトウェアやライブラリをインストールするDockerfileを作成します。

dockerfile
FROM python:3-alpine

ENV PYTHONIOENCODING utf-8
WORKDIR /app

RUN apk add --update \
        wget \
    # Add chromium and dependences
        udev \
        ttf-freefont \
        chromium \
        chromium-chromedriver \
    # Add Japanese font
    && mkdir noto \
    && wget -P /app/noto https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \
    && unzip /app/noto/NotoSansCJKjp-hinted.zip -d /app/noto \
    && mkdir -p /usr/share/fonts/noto \
    && cp /app/noto/*.otf /usr/share/fonts/noto \
    && chmod 644 -R /usr/share/fonts/noto/ \
    && fc-cache -fv \
    && rm -rf /app/noto \
    # Add selenium
    && pip install selenium

Dockerイメージのビルド

Dockerfileを使用してDockerイメージを作成します。
ビルドコマンドを使用してDockerイメージをビルドし、タグ付けします。

cd /xxx/AutomatedTest
docker build -t automatedtest .

テストの実行

ビルドしたDockerイメージからDockerコンテナを起動します。
また、実行環境を再起動した際にもDockerコンテナが起動しておくように自動起動の設定をしておきます。

docker run -v /xxx/AutomatedTest/app:/app  -it -d --name automatedtest automatedtest
docker update --restart=always automatedtest

起動していることを確認したら、テストを実行します。

docker ps
docker container exec automatedtest python publicTest.py

実行結果

テストに成功すると特にメッセージ等は表示されませんが、失敗するとコマンドライン上に以下のようなエラーメッセージが表示されます。tempフォルダに画像が保存されますので、テストに失敗した際はエラーメッセージと画像からエラーの調査を行えます。

'WebDriver' object has no attribute 'find_element_by_xpath'

おわりに

今回はSeleniumとDockerを組み合わせてテスト自動化をやってみました。
自動化することで作業を減らせることはもちろんですが、作業のことを考えなくても良くなるのは大きいと思いました。ただ、システムの更新頻度が高く、特にデザインがコロコロ変わるシステムでは、テストプログラムの変更も多くなるので、工夫が必要になりそうです。
自動化を検討している方は是非、試してみてください。

参考文献

https://hodalog.com/use-selenium-on-docker/
https://webrage.jp/techblog/automation_tool/
https://qiita.com/jun2014/items/8cabbd52830904af49af

CareNet Engineers

Discussion