概要
本章では、CircleCIというCIツールを使って、Python+Seleniumで作成した自動テストを定期的に実行する方法を解説します。
公式のドキュメント(CircleCIのドキュメントへようこそ - CircleCI)を参考にしつつ、やってみてください。
用意するもの
- GitHubのアカウント
- CircleCIのアカウント
- CircleCI を始める - CircleCI を参照
- GitHubアカウントでログインすると、連携が簡単です
- Selenium + Python + pytestで作成した自動テスト
- 別途サンプルを用意しておくので、無い場合は無いでも大丈夫です。ご自身で動かしたい自動テストがある方は、ソースコード一式と、テストを動かすためにpipで入れるものリストを用意しておいてください。
CircleCIでSelenium+Pythonのコードを実行する
1. GitHubにリポジトリをつくる
最初に、GitHubにリポジトリを作ります。ここではYoshikiIto/Selenium-circleciを作成した、として進めます。
2. コードを追加
動かしたいテストがある方はそのファイルを。ない方は下記のサンプルをお使いください。
Selenium-circleci
|- test_google.py <- 新規追加
test_google.py
というファイル名で、以下のコードをリポジトリ内に作成します。
import pytest
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
class TestGoogle:
driver = webdriver.Chrome(ChromeDriverManager().install())
def setup_class(cls):
cls.driver = webdriver.Chrome(ChromeDriverManager().install())
cls.driver.maximize_window()
def setup_method(self):
self.driver.get("https://google.com")
def test_case(self):
driver = self.driver
driver.save_screenshot("test-reports/result_001.png")
driver.find_element_by_css_selector("#tsf > div:nth-child(2) > div > div.RNNXgb > div > div.a4bIc > input").send_keys("hoge")
driver.save_screenshot("test-reports/result_002.png")
driver.find_element_by_css_selector("#tsf > div:nth-child(2) > div > div.FPdoLc.VlcLAe > center > input.gNO89b").click()
driver.save_screenshot("test-reports/result_003.png")
assert driver.title.count('hoge'), "ページタイトルにhogeが含まれていること"
def teardown_class(cls):
cls.driver.quit()
上記のコードを正しく実行できた場合、以下のような動作をします。
- Googleのトップページを開く
- スクリーンショットを撮る
- 検索バーに「hoge」と入力する
- スクリーンショットを撮る
- Google検索ボタンを押す
- ページ遷移後のスクリーンショットを撮る
なお、上記のコードではSergeyPirogov/webdriver_managerを使用しているため、ローカルで動かす場合には以下のコマンドでインストールしてから実行してください。
$ pip install webdriver_manager
3. pipでインストールするパッケージの一覧を作成
Selenium-circleci
|- test_google.py
|- requirements.txt <- 新規追加
pytestや、前項のwebdriver_managerなど、実行前にpipでインストールする必要があるものをまとめたrequirements.txt
を作成します。
※これはCircleCIの機能というわけではなく、複数のパッケージを一括インストールするためのpip側の仕組みです。参考:Python, pipでrequirements.txtを使ってパッケージ一括インストール | note.nkmk.me
requirements.txt
の内容は以下です。
pytest
selenium
webdriver_manager
ご自身で用意したテストを動かす場合は、別途使っているパッケージもrequirements.txt
の中に書いておいてください。
4. 設定ファイルを追加
Selenium-circleci
|- test_google.py
|- requirements.txt
|- .circleci
|- config.yml <- 新規追加
CircleCIで実行したい処理の詳細は、.circleci/config.yml
という設定ファイルに記載していきます。
※CircleCIのバージョンによってconfigの場所が違うので、ネット上の情報を見るときにはどのバージョンの話なのかを気にするようにしてください。
詳細な解説は本ドキュメントの後半で行うので、一旦はこの通りでやってみましょう。
# Python CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-python/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
# use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers`
- image: circleci/python:3.7.3-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# - image: circleci/postgres:9.4
working_directory: ~/repo
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "requirements.txt" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: install dependencies
command: |
python3 -m venv venv
. venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
- run: mkdir test-reports
- save_cache:
paths:
- ./venv
key: v1-dependencies-{{ checksum "requirements.txt" }}
# run tests!
# this example uses Django's built-in test-runner
# other common Python testing frameworks include pytest and nose
# https://pytest.org
# https://nose.readthedocs.io
- run:
name: run tests
command: |
. venv/bin/activate
pytest test_google.py -v --junit-xml=test-results/regression/results.xml
- store_artifacts:
path: test-reports/
destination: test-reports
- store_test_results:
path: test-results
workflows:
version: 2
normal_workflow:
jobs:
- build
schedule_workflow:
triggers:
- schedule:
cron: "1 7 * * *" # UTCで記述。-9
filters:
branches:
only:
- master
jobs:
- build
ここまでできたら、GitHubのリモートリポジトリにすべてプッシュしておいてください。
4. CircleCI上でSet Up Project
CircleCiにログインします。
ここに最初のプロジェクトの始め方が書いてあります。さっと読んで、「Start a Project」ボタンをクリックします。
GitHub上のリポジトリが表示されるので、この中から今回のテスト用に作成したリポジトリ(ここではSelenium-circleci)の「Set Up Project」ボタンをクリックします。
Operating SystemではLinux、LanguageではPythonを選びましょう。
「Copy to Clipboard」のところは、すでにconfig.yml
ファイル作成済みのため、行わなくて大丈夫です。
5. CircleCI上でビルド
CircleCIでジョブの実行を行うことを「ビルドする」と言います(プログラムのソースコードのビルドと混同しやすいので注意してください)。
水色の「Start building」ボタンをクリックしましょう。ビルドが終わると結果が表示されます。
ビルドが正しく実行された場合の例が以下です。
test_google.py
にわざと失敗するassertを追加してみましょう。
assert driver.title.count('hoge'), "ページタイトルにhogeが含まれていること"
assert driver.title.count('foobar'), "ページタイトルにfoobarが含まれていること" # わざと失敗させる
この状態でビルドを実行し、失敗した状態の例が以下です。
テストレポートを出力する
ここまでの手順では、テスト実行の結果がビルドのPass/Failとしてしか表示されていませんでした。しかし、実際にテストを行う場合、何ケース実行してそのうち何ケースがPassしたのかなどのレポートが欲しくなります。
簡単に使えるものとして、pytest-htmlを使って、レポート表示をしてみましょう。
出力したレポートのサンプルが以下です。
1. requirements.txtの編集
pytest-html
が必要なので、pipでインストールできるようrequirements.txt
を以下のように編集しましょう。
pytest
selenium
webdriver_manager
pytest-html
2. config.ymlの編集
config.yml
を編集して、実際にpytestコマンドでテストを行う際にHTMLレポートも出力するようにオプションを追加します。
以下、編集後のconfig.yml
の抜粋です。
- run:
name: run tests
command: |
. venv/bin/activate
pytest test_google.py -v --junit-xml=test-results/regression/results.xml --html=test-reports/report.html --self-contained-html
3. ビルド
ここまでできたら、CircleCIでビルドをします。
ビルドの結果、今回の設定ではArtifacts内にreport.html
が出力されています。
config.yml
の解説
Dockerイメージの指定
CircleCIで自動テストを動かす際は、使っている言語ごとに用意されているDockerイメージを指定します。
言語のバージョンも細かく選ぶことができ、一覧はPre-Built CircleCI Docker Images - CircleCIにあります。
Seleniumの自動テストを実行するにあたって気を付ける点は、末尾に-browsers
をつけることです。
docker:
# specify the version you desire here
# use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers`
- image: circleci/python:3.7.3-browsers
CircleCI公式のconfig.yml
のコメントにも同様の内容が書いてあります(prefixじゃなくてpostfixでは? という気もしますが)
stepsの記述
基本的に、実行したい処理のまとまりごとにrunコマンドを設定していきます。
pipを使ったモジュールのインストールが以下です。
- run:
name: install dependencies
command: |
python3 -m venv venv
. venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
都度pipのupgradeと、各種モジュールのインストール(実際には最新版の有無確認)が走るようにしています。それほど時間のロスにはなっていません。
次に、テスト実行結果の格納用にmkdir
コマンドを実行しています。
- run: mkdir test-reports
テスト実行コマンドがこちらです。
- run:
name: run tests
command: |
. venv/bin/activate
pytest test_google.py -v --junit-xml=test-results/regression/results.xml --html=test-reports/report.html --self-contained-html
pytestの実行コマンドに、追加でxmlのレポートとhtmlのレポートを出力させています。
JUnit形式のxmlを出力させることで、CircleCIがテスト結果の収集や表示を行ってくれます。HTMLのレポート出力は人間用です。
最後に、出力したファイルを保存する処理です。
- store_artifacts:
path: test-reports/
destination: test-reports
- store_test_results:
path: test-results
store_artifacts
を実行することで、コンテナ内に保存した結果をビルド結果のページから見られるようにコピーします。
ここまでで、GitHubへプッシュする毎にテストが実行される状態にできます。追加で、「毎日16時にビルドを実行する」という設定もしてあります。
workflows:
version: 2
normal_workflow:
jobs:
- build
schedule_workflow:
triggers:
- schedule:
cron: "1 7 * * *" # UTCで記述。-9
filters:
branches:
only:
- master
jobs:
- build
cron
の行が、この定期実行の具体的な時間指定です。ジョブの実行を Workflow で制御する - CircleCIを参考に、好きな時間に設定してみましょう。
参考
-
Configuring CircleCI - CircleCI
- テスト結果の格納時、フォルダ名を任意で設定する点の説明など
-
CircleCI を設定する - CircleCI
- YAMLの書き方