最近、私の関わっている案件で、ブラウザテストを自動化しようという話が出てきました。
それで色々と調べてみたところ、どうやらSeleniumを使った自動テストをBrowserStack上で動かすのが良さそうだ、ということになったので、実際にサンプルコードを書いて、どんなものか検証してみました。
この記事では、そこで得られた知見を共有したいと思います。
ツールの紹介
はじめに、SeleniumとBrowserStackについて紹介します!
Selenium
Seleniumは、ブラウザの操作を自動化するツールです。
従来のブラウザテストでは、同じような操作(例えば、「フォームを記入して送信ボタンを押す」というような操作)を何度も人の手で行わなければなりませんでした。なかなかつらい作業ですよね。
Seleniumはこれらの作業を全て自動で行ってくれます!
もちろんテストコードを書く必要はありますが、クロスブラウザテストや回帰テストなどで同じテストを繰り返し実施する労力は、かなり削減できるのではないでしょうか。
Seleniumは、ChromeやSafari、IE、FireFox、Operaなど、主要なブラウザを操作することができます。また、JavaやC#、Python、Ruby、JavaScriptなど、様々な言語に対応しています。
今回のサンプルではJavaScript(Node.js)でコードを書いていきます。
ただし、Selenium自体はあくまでブラウザ操作のためのツールであり、テスト機能は持ち合わせていません。
テストを書くにあたって、今回は、JavaScriptのテストフレームワークであるMochaを併用します。
BrowserStack
BrowserStackは、様々なブラウザ環境を提供してくれるクラウドサービスです。
ブラウザテストを実施するにあたって意外と手間がかかるのが、テスト環境の用意ではないでしょうか。
Safariでの動作を確認するためにMacを用意したり、IEでの確認のためにWindows機を用意したりと、結構、大変です。しかもIEの場合、一つのマシンに一つのバージョンしか入れられないため、IE9、10、11をテストしようとしたら、PCなりVMなりを3つ用意しなければならなかったりします
このような課題を解決してくれるのがBrowserStackです!
BrowserStackは2000以上のデバイスとブラウザをクラウド上で提供しており、ユーザーはそれらの環境を自由に利用することができます(提供されているOSとブラウザの一覧はこちら)。
しかもそれだけではなく、テスト中の画面のスクリーンショットや動画を自動で撮ってくれたりといった、便利な機能もついています。また今回は扱いませんが、自動テストだけでなく、手動でのテストにも対応しています。
このように至れり尽くせりなサービスなのですが・・・有料です
自動テストプランの場合、1か月1ユーザーにつき、129ドルかかります(年額購入の場合。詳しくはこちら)。
今回のデモでは無料トライアルプランを利用します。無料でも100分の自動テストと100枚のスクリーンショットが取れますので、ちょっと試してみる分には十分でしょう。
デモ概要
それではさっそくデモに移りましょう。
今回のデモでは、こちらのフォーム画面のIE11動作テストを自動化します。
以下、
- BrowserStackへのユーザー登録
- テストコード作成
- テスト実施
の順で説明していきます。
BrowserStackユーザー登録
テストコードを書く前に、BrowserStackのユーザー登録を行っておきます。
BrowserStackトップ画面のGet started free
もしくはFREE TRIAL
ボタンからアカウント登録ができます。
ログインすると、下のようなダッシュボード画面が表示されます(表示されない場合はメニューのProducts
からAutomate
を選択してみてください)。
テストのログやスクリーンショット、動画はこのダッシュボード画面から確認することができます。
テストコード作成
テストコードを書いていきます。
上でも述べたように、今回はSeleniumと合わせて、テストフレームワークのMocahを使用し、JavaScript(Node.js)でコードを書いていきます。Node.jsがない方はインストールしておきましょう。
ディレクトリの作成
まず適当な場所にテストコードを格納するディレクトリ(今回のデモではdemo-test
)を作成します。
ディレクトリ構造は任意ですが、今回のデモでは以下のようにします。
demo-test/
├ conf/ BrowserStackを使うための設定ファイルを格納
└ test/ テストコードを格納
demo-test
に移動し、npm init -y
コマンドを実行します。
cd /Users/MyName/Project/demo-test
npm init -y
このコマンドを実行することで、ディレクトリ内にプロジェクトの情報等が記されたpackage.json
ファイルが作成されます。
モジュールのインストール
SeleniumとMochaを使用するために、以下のコマンドでインストールします。
npm i -D selenium-webdriver mocha
package.json
を確認して、次のような行が追記されていればOKです!
"devDependencies": {
"mocha": "^6.1.4",
"selenium-webdriver": "^4.0.0-alpha.1"
}
テストコードファイルの作成
test
ディレクトリにテストコード本体であるform-test.js
を、conf
ディレクトリにBrowserStackを使用するのに必要な情報をまとめたtest.conf.js
をそれぞれ作成します。
以下、test.conf.js
、form-test.js
の順で見ていきます。
test.conf.js
require('dotenv').config();
exports.capabilities = {
'browserstack.user': process.env.BROWSERSTACK_USERNAME || 'USERNAME',
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY || 'ACCESS_KEY',
'build': 'mocha-browserstack',
'name': 'form_test',
'browserstack.debug': 'true',
'browserName': 'internet explorer',
'version': '11',
'platform': 'WINDOWS'
};
このファイルには、BrowserStackのユーザー名やアクセスキー、テストするOSやブラウザの種類といった、BrowserStack上でテストを動かすのに必要な情報が書かれています。
capabilities
オブジェクトの下三行に注目してください。
'browserName': 'internet explorer',
'version': '11',
'platform': 'WINDOWS'
ここでテストに使うブラウザとそのバージョン、OSを指定します。
他のブラウザでテストしたいときはここを変えればいいんですね。
続いて上二行に注目してください。
'browserstack.user': process.env.BROWSERSTACK_USERNAME || 'USERNAME',
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY || 'ACCESS_KEY',
ここにBrowserStackにアクセスするために必要なユーザー名とアクセスキーを記入します。
ユーザー名およびアクセスキーは、BrowserStackのダッシュボード画面左のUsername and Access Keys
をクリックすると表示されます。
ここで一点、注意事項があります。
ユーザー名とアクセスキーの値をそのまま張り付けてしまっても動くのですが、こうしたセキュリティ上重要な情報をコードに書いてしまうのはちょっと心配です。
ローカルでコードを管理する分にはいいのですが、GitHub等で管理する場合、アクセスキーなどの情報がそのままネット上に公開されてしまいます。
これらの情報は環境変数として.env
ファイルにまとめて、gitの管理からも外してしまうのがよいでしょう。
.env
ファイルを作成するために、dotenvというモジュールをインストールします。
npm i dotenv
test.conf.js
の1行目でdotenv
を読み込みます。
require('dotenv').config();
demo-test
直下に.env
ファイルを作成します。中身は以下のようにしてください。
BROWSERSTACK_USERNAME=ユーザー名
BROWSERSTACK_ACCESS_KEY=アクセスキー
.gitignore
ファイルに.env
を追記します。
.env
これでユーザー名とアクセスキーを安全に使用することができます
以上、テストに使うブラウザ・OSの設定と、ユーザー名・アクセスキーの設定を行いました。
他のプロパティについては、公式ドキュメントを参照してみてください。
form-test.js
const { Builder, By } = require("selenium-webdriver");
const assert = require("assert");
const conf_file = 'conf/test.conf.js';
const caps = require('../' + conf_file).capabilities;
let driver;
describe("入力フォーム デモ", function() {
before(function() {
driver = new Builder()
.usingServer('https://hub-cloud.browserstack.com/wd/hub')
.withCapabilities(caps)
.build();
process.on("unhandledRejection", console.dir);
});
after(function() {
return driver.quit();
});
it("コメントの必須入力チェック その1", async function() {
// テスト対象のページへアクセス
await driver.get(
"http://glacial-dusk-36576.herokuapp.com/"
);
// 名前だけ入力してSubmitする
await driver.findElement(By.name("name")).sendKeys("Qiita太郎");
await driver.findElement(By.id("submit-button")).click();
// エラーメッセージを取得して、文言が正しいかチェックする
const errorMsg = await driver
.findElement(By.className("error-message"))
.getText();
assert.equal(errorMsg, "コメントを入力してください。");
});
it("コメントの必須入力チェック その2", async function() {
// テスト対象のページへアクセス
await driver.get(
"http://glacial-dusk-36576.herokuapp.com/"
);
// 名前とコメントを入力してSubmitする
await driver.findElement(By.name("name")).sendKeys("Qiita太郎");
await driver.findElement(By.name("comment")).sendKeys("こんにちは");
await driver.findElement(By.id("submit-button")).click();
// 成功メッセージを取得して、文言が正しいかチェックする
const successMsg = await driver
.findElement(By.className("success-message"))
.getText();
assert.equal(successMsg, "コメントを送信しました。");
});
});
こちらがテストコード本体になります。上から順に見ていきましょう。
まず最初の4行で必要なモジュールを読み込んでいます。
const { Builder, By } = require("selenium-webdriver");
const assert = require("assert");
const conf_file = 'conf/test.conf.js';
const caps = require('../' + conf_file).capabilities;
2行目でrequire("assert")
していますが、実はMochaにはアサーション機能がついていないため、ここでNode.jsのassertモジュールを読み込んでいます。
3、4行目では先ほど作成したtest.conf.js
を読み込んでいます。
Mochaの仕様で、テストはdescribe
メソッドの中に書きます。
個々のテストはit
の中に書いていきます。テスト実施前に行う処理はbefore
、すべてのテストが終わった後の処理はafter
の中に書きます。
before(function() {
driver = new Builder()
.usingServer('https://hub-cloud.browserstack.com/wd/hub')
.withCapabilities(caps)
.build();
process.on("unhandledRejection", console.dir);
});
まず、before
メソッド内で、caps
の情報をもとにウェブドライバーを作成しています。
この後、二つのit
テストが実行され、最後にafter
メソッド内でブラウザを閉じ、テストを終了します。
after(function() {
return driver.quit();
});
it
テストの中身を見ていきましょう。
it("コメントの必須入力チェック その1", async function() {
// テスト対象のページへアクセス
await driver.get(
"http://glacial-dusk-36576.herokuapp.com/"
);
// 名前だけ入力してSubmitする
await driver.findElement(By.name("name")).sendKeys("Qiita太郎");
await driver.findElement(By.id("submit-button")).click();
// エラーメッセージを取得して、文言が正しいかチェックする
const errorMsg = await driver
.findElement(By.className("error-message"))
.getText();
assert.equal(errorMsg, "コメントを入力してください。");
});
コードとコメントを見れば、大体の流れは把握できると思います
driver
以下の部分がSeleniumが提供しているメソッドですね。
.findElement(By)
でHTMLの要素を取得します。By
以下は、idやname属性値、CSSクラス名等を指定することができます。
さらに.sendKeys
や.click
といったメソッドをチェーンすることができます。
最後にassert.equal
で、出てきたエラーメッセージと第二引数の文字列が等しいかどうか判定しています。
以上が、今回のデモで使用するテストコードになります。
テスト実施
いよいよテストを実施します!
コマンドの設定
コマンドラインからテストを実行できるように、package.json
のscripts
に以下のように追記します。
"scripts": {
"test:form": "mocha test/form-test.js --no-timeout"
}
コマンドラインでtest:form
コマンドを打つと、mochaを使ってtest/form-test.js
に書かれたテストが実行されます。
--timeout 10000
のようにして、タイムアウト時間(ミリ秒)を設定することもできますが、今回はタイムアウト無し(--no-timeout
)で実行します。
それではテストを走らせましょう。
以下のコマンドを実行してください。
npm run test:form
テストが実行されました!
コマンドラインにテスト結果が表示されていることと思います。
BrowserStackで確認
BrowserStackのダッシュボード画面に行ってみましょう。
先ほど実施したテストが表示されています。テスト名をクリックします。
テスト実行結果の詳細が表示されます。テスト実行時の動画も撮られていますね。
ログもきちんと取れています。
操作ごとのスクリーンショットも撮られています。画像と動画はもちろんダウンロードできます。
とまあこんな感じです。
自動でスクショを撮ってくれるのでエビデンス作成の手間が省けますし、動画を見ればどこでテストがつまづいたか簡単に確認できますね!
まとめ
以上、SeleniumとBrowserStackを使って、ブラウザテストを自動化してみました。
正直、これくらいのテストであれば手でやった方が早いのですが、今後、どんどんテストが増え、また繰り返し実行しなければならない状況になった時にはやはり、こうした自動化ツールが頼りになるのだと思います。
参考
今回、テストコードを書くにあたって、以下のページを参考にしました。
Node.jsとSeleniumでWebアプリのUIテストを自動化(2018年版)
Selenium examples for Mocha and BrowserStack Automate