14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ベリサーブAdvent Calendar 2019

Day 9

CircleCIでSeleniumのテストを定期実行する

Last updated at Posted at 2019-12-08

概要

本章では、CircleCIというCIツールを使って、Python+Seleniumで作成した自動テストを定期的に実行する方法を解説します。

公式のドキュメント(CircleCIのドキュメントへようこそ - CircleCI)を参考にしつつ、やってみてください。

用意するもの

  • GitHubのアカウント
  • CircleCIのアカウント
  • Selenium + Python + pytestで作成した自動テスト
    • 別途サンプルを用意しておくので、無い場合は無いでも大丈夫です。ご自身で動かしたい自動テストがある方は、ソースコード一式と、テストを動かすためにpipで入れるものリストを用意しておいてください。

CircleCIでSelenium+Pythonのコードを実行する

1. GitHubにリポジトリをつくる

最初に、GitHubにリポジトリを作ります。ここではYoshikiIto/Selenium-circleciを作成した、として進めます。

CircleCI_002.PNG

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()

上記のコードを正しく実行できた場合、以下のような動作をします。

  1. Googleのトップページを開く
  2. スクリーンショットを撮る
  3. 検索バーに「hoge」と入力する
  4. スクリーンショットを撮る
  5. Google検索ボタンを押す
  6. ページ遷移後のスクリーンショットを撮る

なお、上記のコードでは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にログインします。

CircleCI_001.PNG

ここに最初のプロジェクトの始め方が書いてあります。さっと読んで、「Start a Project」ボタンをクリックします。

CircleCI_003.PNG

GitHub上のリポジトリが表示されるので、この中から今回のテスト用に作成したリポジトリ(ここではSelenium-circleci)の「Set Up Project」ボタンをクリックします。

CircleCI_004.PNG

Operating SystemではLinux、LanguageではPythonを選びましょう。

「Copy to Clipboard」のところは、すでにconfig.ymlファイル作成済みのため、行わなくて大丈夫です。

5. CircleCI上でビルド

CircleCIでジョブの実行を行うことを「ビルドする」と言います(プログラムのソースコードのビルドと混同しやすいので注意してください)。

水色の「Start building」ボタンをクリックしましょう。ビルドが終わると結果が表示されます。

ビルドが正しく実行された場合の例が以下です。

CircleCI_005.PNG

test_google.pyにわざと失敗するassertを追加してみましょう。

assert driver.title.count('hoge'), "ページタイトルにhogeが含まれていること"
assert driver.title.count('foobar'), "ページタイトルにfoobarが含まれていること"  # わざと失敗させる

この状態でビルドを実行し、失敗した状態の例が以下です。

CircleCI_006.PNG

テストレポートを出力する

ここまでの手順では、テスト実行の結果がビルドのPass/Failとしてしか表示されていませんでした。しかし、実際にテストを行う場合、何ケース実行してそのうち何ケースがPassしたのかなどのレポートが欲しくなります。

簡単に使えるものとして、pytest-htmlを使って、レポート表示をしてみましょう。

出力したレポートのサンプルが以下です。

CircleCI_007.PNG

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が出力されています。

CircleCI_008.PNG

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を参考に、好きな時間に設定してみましょう。

参考

14
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?