Help us understand the problem. What is going on with this article?

CentOS7 + behat3 + Selenium2導入まとめ

More than 1 year has passed since last update.

はじめに

プロジェクト内で機能追加をする際、デグレの調査がかなりめんどくさいと思ったのと、
毎回同じテストを繰り返す時間がもったいなく感じたので、自動テストを導入しました。

今回は、CentOS7でbehat3 + Selenium2でやってみたのでまとめました。

環境

  • Windows(8.1、10で確認)
  • Vagrant 1.9.7
  • VirtualBox 5.1.~
  • CentOS7.3
  • PHP7.1(今回は7.1で実施しました。)

事前準備

必要なパッケージをインストールします。

  • firefox
    yum -y install firefox

  • 仮想ディスプレイを作る
    yum -y install xorg-x11-server-Xvfb
    仮想ディスプレイの出力先も同時に設定しましょう。
    vi ~/.bash_profileで以下を記載します。
    export DISPLAY=:1
    編集後は再読み込みさせましょう。
    source ~/.bash_profile

Javaのインストール

Selenium2を動作させるにはJavaをインストールする必要があるため、Javaもインストールしましょう。
yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel

Selenium本体をダウンロード

Selenium本体をダウンロードします。
SeleniumはFirefoxのバージョンによって動くバージョンが異なります。
適宜環境に合わせて変更してください。
wget http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.1.jar

CentOSの日本語化

日本語化しないと、日本語が文字化けします。
今回はCentOS7の日本語化です。

[root@localhost behat]# yum -y install ibus-kkc vlgothic-*
[root@localhost behat]# localectl set-locale LANG=ja_JP.UTF-8
[root@localhost behat]# source /etc/locale.conf

behat準備

composer準備

composerでbehatをインストールします。
任意のディレクトリで
composer init
を実行し、composer.jsonに下記を記載します。
(composer本体のインストール方法は様々な記事があるので省略します。)

composer.json
{
    "require-dev": {
        "behat/behat": "3.*@stable",
        "behat/mink": "1.*@stable",
        "behat/mink-extension": "*",
        "behat/mink-goutte-driver": "*",
        "behat/mink-sahi-driver": "*",
        "behat/mink-selenium2-driver": "*",
        "behat/mink-zombie-driver": "*"
    },
    "config": {
        "bin-dir": "bin/"
    }
}

記載後、composer installを実行してください。

behatの初期化

composer installが完了したあと、実行したディレクトリにbinディレクトリが生成されます。
./bin/behat --initを実行し、behatの初期化を行ってください。

[root@localhost behat]# ./bin/behat --init
+d features - place your *.feature files here
+d features/bootstrap - place your context classes here
+f features/bootstrap/FeatureContext.php - place your definitions, transformatio
ns and hooks here

behatの設定

behat.ymlをサンプルからコピーして設定を追加します。
cp ./vendor/behat/mink-extension/behat.yml.dist behat.yml

behat.yml
default:
  suites:
    default:
      path: %paths.base%/features
      # FeatureContextを追加
      contexts: [FeatureContext,Behat\MinkExtension\Context\MinkContext]
  extensions:
    Behat\MinkExtension:
      # googleで検索シナリオにしたいので、base_urlを変更
      base_url: https://www.google.co.jp/
      # firefoxで検索する
      browser_name: firefox
      sessions:
        default:
          selenium2:
            capabilities: {"browser":"firefox","version":"*"}

シナリオ記述方法

登録シナリオの確認

現在登録されている有効なシナリオは下記コマンドで確認できます。

[root@localhost behat]# ./bin/behat -dl
default | 前提< /^(?:|ユーザーは )ホームページを表示している$/
default | もし< /^(?:|ユーザーは )ホームページへ移動する$/
default | 前提< /^(?:|ユーザーは )"(?P<page>[^\s]+)" を表示している$/u
default | もし< /^(?:|ユーザーが )"(?P<page>[^\s]+)" へ移動する$/u
default | もし< /^(?:|ユーザーが )ページをリロードする$/u
default | もし< /^(?:|ユーザーが )履歴の前のページに戻る$/u
default | もし< /^(?:|ユーザーが )履歴の次のページヘ進む$/u
default | もし< /^(?:|ユーザーが )"(?P<button>(?:[^"]|\\")*)" ボタンをクリックす
る$/u
default | もし< /^(?:|ユーザーが )"(?P<link>(?:[^"]|\\")*)" のリンク先へ移動する
$/u
default | もし< /^(?:|ユーザーが )"(?P<field>(?:[^"]|\\")*)" フィールドに "(?P<v
alue>(?:[^"]|\\")*)" と入力する$/u
default | もし< /^(?:|ユーザーが )"(?P<field>(?:[^"]|\\")*)" フィールドに以下の
値を入力する:$/u
default | もし< /^(?:|ユーザーが )"(?P<value>(?:[^"]|\\")*)" という値を "(?P<fie
ld>(?:[^"]|\\")*)" に入力する$/u
default | もし< /^(?:|ユーザーが)次のように入力する:$/u
default | もし< /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" という値を "(?P<se
lect>(?:[^"]|\\")*)" から選択する$/u
default | もし< /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" という値を "(?P<se
lect>(?:[^"]|\\")*)" から追加で選択する$/u
default | もし< /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" にチェックをつける
$/u
default | もし< /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" のチェックをはずす
$/u
default | もし< /^(?:|ユーザーが)パス "(?P<path>[^"]*)" にあるファイルを "(?P<fi
eld>(?:[^"]|\\")*)" に添付する$/u
default | ならば< /^(?:|ユーザーが )(?P<page>[^\s]+) を表示していること$/u
default | ならば< /^(?:|ユーザーが )ホームページを表示していること$/u
default | ならば< /^(?i)url(?-i)が (?P<pattern>"(?:[^"]|\\")*") にマッチすること
$/u
default | ならば< /^レスポンスコードが (?P<code>\d+) であること$/u
default | ならば< /^レスポンスコードが (?P<code>\d+) ではないこと$/u
default | ならば< /^(?:|画面に )"(?P<text>(?:[^"]|\\")*)" と表示されていること$/
u
default | ならば< /^(?:|画面に )"(?P<text>(?:[^"]|\\")*)" と表示されていないこと
$/u
default | ならば< /^(?:|画面に )"(?P<pattern>"(?:[^"]|\\")*")" にマッチするテキ
ストが表示されていること$/u
default | ならば< /^(?:|画面に )"(?P<pattern>"(?:[^"]|\\")*")" にマッチするテキ
ストが表示されていないこと$/u
default | ならば< /^レスポンスに "(?P<text>(?:[^"]|\\")*)" が含まれていること$/u

default | ならば< /^レスポンスに "(?P<text>(?:[^"]|\\")*)" が含まれていないこと$
/u
default | ならば< /^"(?P<element>[^"]*)" エレメントに "(?P<text>(?:[^"]|\\")*)"
と表示されていること$/u
default | ならば< /^"(?P<element>[^"]*)" エレメントに "(?P<text>(?:[^"]|\\")*)"
と表示されていないこと$/u
default | ならば< /^"(?P<element>[^"]*)" エレメントに "(?P<value>(?:[^"]|\\")*)"
 という値が含まれていること$/u
default | ならば< /^"(?P<element>[^"]*)" エレメントに "(?P<value>(?:[^"]|\\")*)"
 という値が含まれていないこと$/u
default | ならば< /^(?:|画面に )"(?P<element>[^"]*)" エレメントが表示されている
こと$/u
default | ならば< /^(?:|画面に )"(?P<element>[^"]*)" エレメントが表示されていな
いこと$/u
default | ならば< /^"(?P<field>(?:[^"]|\\")*)" フィールドに "(?P<value>(?:[^"]|\
\")*)" が含まれていること$/u
default | ならば< /^"(?P<field>(?:[^"]|\\")*)" フィールドに "(?P<value>(?:[^"]|\
\")*)" が含まれていないこと$/u
default | ならば< /^(?:|画面に )(?P<num>\d+) 個の "(?P<element>[^"]*)" エレメン
トが表示されていること$/u
default | ならば< /^チェックボックス "(?P<checkbox>(?:[^"]|\\")*)" のチェックが
ついていること$/u
default | ならば< /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" (?:is|should be)
checked$/
default | ならば< /^チェックボックス "(?P<checkbox>(?:[^"]|\\")*)" のチェックが
はずれていること$/u
default | ならば< /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" should (?:be unch
ecked|not be checked)$/
default | ならば< /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" is (?:unchecked|n
ot checked)$/
default | ならば< /^現在のURLを表示$/
default | ならば< /^最後のレスポンスを表示$/u
default | ならば< /^最後のレスポンスをブラウザで表示$/u

シナリオ記述方法(1回テスト)

1回のみテストを行うシナリオを記載します。
今回はgoogleでQiitaを検索するシナリオを記載します。

features/test1.feature
# language: ja
#
フィーチャ: グーグルでQiitaを検索

    @javascript
    シナリオ: グーグルでQiitaを検索
        前提 ホームページを表示している
        もし "q" フィールドに "Qiita" と入力する
            かつ "Google 検索" ボタンをクリックする
        ならば "https://qiita.com/" と表示されていること

シナリオ記述方法(繰り返しテスト)

繰り返しテストを行うシナリオを記載します。
今回はgoogleでQiitaとQiita Advent Calendarを検索するシナリオを記載します。

features/test2.feature
# language: ja
#
フィーチャ: グーグルでQiitaとQiita Advent Calendarを検索

    @javascript
    シナリオテンプレート: グーグルでQiitaとQiita Advent Calendarを検索
        前提 ホームページを表示している
        もし "q" フィールドに "<search>" と入力する
        かつ "Google 検索" ボタンをクリックする
        ならば "<URL>" と表示されていること

    :
        | search | URL |
        | Qiita | https://qiita.com/ |
        | Qiita Advent Calendar | https://qiita.com/advent-calendar |

「シナリオ:」となっている箇所が「シナリオテンプレート:」になっています。
また、繰り返しテストの中で、値を変えたい箇所を<>で囲むことで変数として入力されます。
変数は「例:」として記述します。

シナリオ実行

CentOS上で完結させるため、ブラウザを起動させます。

  • Xvfb(仮想ディスプレイ)をバックグラウンドで起動
    Xvfb :1 -screen 0 1024x768x24 &

  • firefoxをバックグラウンドで起動
    firefox &

  • 起動の確認
    jobs

また、Seleniumも起動させます。
java -jar selenium-server-standalone-2.53.1.jar

Seleniumの起動が完了を待ちましょう。
(下記ログを確認)
INFO - Selenium Server is up and running

すべての起動が完了したらシナリオを実行させます。
まずは、test1の実行をします。

test1.log
[root@localhost behat]# ./bin/behat features/test1.feature
フィーチャ: グーグルでQiitaを検索

  @javascript
  シナリオ: グーグルでQiitaを検索                       # features/test1.feature:6
    前提 ホームページを表示している                    # Behat\MinkExtension\Context\MinkContext::iAmOnHomepage()
    もし "q" フィールドに "Qiita" と入力する         # Behat\MinkExtension\Context\MinkContext::fillField()
    かつ "Google 検索" ボタンをクリックする           # Behat\MinkExtension\Context\MinkContext::pressButton()
    ならば "https://qiita.com/" と表示されていること # Behat\MinkExtension\Context\MinkContext::assertPageContainsText()

1 個のシナリオ (1 個成功)
4 個のステップ (4 個成功)
0m28.30s (9.60Mb)

すべて成功を確認しました。
続けて、test2を実行します。

test2.log
[root@localhost behat]# ./bin/behat features/test2.feature
フィーチャ: グーグルでQiitaとQiita Advent Calendarを検索

  @javascript
  シナリオテンプレート: グーグルでQiitaとQiita Advent Calendarを検索 # features/test2.feature:6
    前提 ホームページを表示している                    # Behat\MinkExtension\Context\MinkContext::iAmOnHomepage()
    もし "q" フィールドに "<search>" と入力する         # Behat\MinkExtension\Context\MinkContext::fillField()
    かつ "Google 検索" ボタンをクリックする           # Behat\MinkExtension\Context\MinkContext::pressButton()
    ならば "<URL>" と表示されていること # Behat\MinkExtension\Context\MinkContext::assertPageContainsText()

    例:
      | search                | URL                               |
      | Qiita                 | https://qiita.com/                |
      | Qiita Advent Calendar | https://qiita.com/advent-calendar |

2 個のシナリオ (2 個成功)
8 個のステップ (8 個成功)
0m18.39s (10.96Mb)

すべて成功を確認しました。

はまったこと

  • GLIBCXXが全然足りないって言われる
    • CentOS6系だとでます。最新のgccをビルドすると直るようですが、かなり時間がかかります。CentOS7を使用することをおすすめします。
  • Firefoxが起動しない
    • ディスプレイの設定が間違えている or 設定が欠けていると起動しないようです。

まとめ

最初にシナリオを作成するのは結構面倒ですが、一度作ってしまえば繰り返しテストはかなり楽になるかと思います。
今の状態ではテスト結果がログでしかわからないため、次は画面キャプチャを残す方法を投稿します。

参考

Behatで行う、E2Eテスト入門

Behat+Selenium Webdriverで受け入れテストの自動化をやってみた

Vagrant の CentOS で Selenium テストを回したい - Qiita

hatsumi
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした