社内でE2Eテストツールとして、TestCafe の話題が出たため、前回の記事 で試したGaugeとの組み合わせでBDDのようにテストを実行できないか、検証してみました。
実行環境
名前
バージョン
OS
Windows 10 Pro 64bit バージョン2004
Node.js
14.15.2
Yarn
1.22.5
TestCafe
1.10.0
Gauge
1.1.6
なぜTestCafe単体ではなく、Gaugeと組み合わせようと思ったのか
TestCafe単体ではテストは簡潔に記述できるものの、実際の運用に乗せることを考えると、ログインや特定の状態への遷移といった、よくある処理の共通化 は必要であると思います。
TestCafeはメソッドチェーンでテストを簡潔に記述 できますが、共通で前処理を行おうと思うと、ツールのサポートとしてはFixtureのbeforeEachメソッド によるフィクスチャ単位の共通化 しか見つけられませんでした。
Page Object Pattern でも記述できるため、共通処理はPage Objectとして切り出し、フィクスチャやテストから実行することはできそうですが、BDDのように明示的に前処理を記述することは、TestCafe単体ではできないようなので、GaugeないしはCucumber.js といったツールと組み合わせることで、明示的な処理の共通化 ができるか確認できればと考えました。
また、前回はGaugeとJava の組み合わせを試したため、今回はGaugeとJavaScript の組み合わせで、使用感に違いがないかも確認できればと思い、Gauge+TestCafeで試してみることとします。
環境構築
TestCafeのインストール
devexpress.github.io
npmまたはYarnでインストールします。*1
インストールが完了したら、 testcafe -v
でバージョンが確認可能です。記事作成時のバージョンは、1.10.0でした。
また、 testcafe -b
で、利用可能なブラウザ一覧 を確認できます。
$ npm install -g testcafe
$ yarn global add testcafe
$ testcafe -v
1 .10 .0
$ testcafe -b
firefox
chrome
ie
edge
edge-legacy
Gaugeのインストール
前回の記事 と同様の手順で、Windows 用インストーラ ーをダウンロードし、Gaugeをインストールします。
記事作成時のバージョンは、1.1.6でした。
Gauge+TestCafeのサンプルプロジェクトのダウンロード
getgauge-examples/gauge-testcafe にサンプルとなるGitプロジェクトがあったため、ZIPダウンロードおよび展開します。
npmまたはYarnで、依存モジュールのインストール後、テストを実行します。
$ npm install && npm test
$ yarn install && yarn test
TestCafeが起動し、Google Chrome のウィンドウが開きます。
起動時の画面
...が、以下のエラーで失敗しました。
Failed Step: Search for "github TestCafe"
Specification: specs\example.spec:6
Error Message: Error: Timed out
Stacktrace:
Error: Timed out
サンプルテストの修正
specs/example.spec
がテスト仕様、 tests/step_implementation.js
がテスト実装になります。
テスト内容を確認してみると、以下のようになっていました。
Google を開く
「github TestCafe」 で検索
検索結果の最初のリンクのテキストに「GitHub - DevExpress/testcafe:」が含まれるか検証
まず、検索する文字列の入力欄を input[title="Search"]
で取得しようとしているものの、日本語環境ではtitleが「検索」になっているようです。
また、GitHub の検索結果のリンクテキストが、記事作成時点では「DevExpress/testcafe: A Node.js tool to automate end ... - GitHub 」となっているため、検証も失敗します。
それぞれ以下のように変更し、テストを再実行すると成功しました。
検索文字列の入力欄取得を input[title="検索"]
で行うよう step_implementation.js
を変更
example.spec
から渡される検証用の文字列を "GitHub - DevExpress/testcafe:"
から "DevExpress/testcafe:"
に変更
前回と同様、 reports/html-report/index.html
にレポートが出力されます。
Gaugeのテストレポート
実装
いきなり躓きましたが、気を取り直して実装していきます。
テストするブラウザの変更
初期状態では、Google Chrome でのテストのみ実行されました。
コマンドからTestCafeを実行する場合、 testcafe ブラウザ名,ブラウザ名,... JavaScriptテストファイル
でテストするブラウザを追加できるため、それっぽい設定はないかと確認したところ、 tests/testcafe_init.js
に browsers('chrome')
という設定がありました。調べてみると、API を使ってJavaScript から実行できるようです。
browsers(['chrome', 'ie', 'edge'])
のように記述すると、各ブラウザのウィンドウは最初に開きますが、先頭のブラウザにのみテストが実行され、それが終わった段階でテスト終了と判断されます。
おそらく、オーケストレーション を行うGaugeと、テストを実行するTestCafeのライフサイクルの違いが原因かと思います。
ひとまず、Google Chrome 以外にも、 browsers('ie')
でInternet Explorer 、 browsers('edge')
でChromium 版Microsoft Edge でテストを実行できることは確認できました。
テスト仕様の追加
前回と同じMarkdown を、 specs/search.spec
に保存しました。
テスト実装の記述
当初は tests/search_steps.js
を追加して検証しようとしたのですが、GaugeではJavaScript でテストを実装する場合、 tests/step_implementation.js
にしかステップを記述できないようです。
ステップ内で実行する関数の内容を別ファイルに書いてimportしたりはできそうですが、ひとまず tests/step_implementation.js
に以下を追記します。
なお、変数 _
と Selector
は、それぞれTestCafeのTestController 、およびSelector になります。
step('検索エンジンのURL <url> を開く' , async (url) => {
await _.navigateTo(url);
} );
step('検索文字列入力欄 <inputSelector> を取得する' , async (inputSelector) => {
const searchTextInput = Selector(inputSelector).with ({ boundTestRun: _ } );
gauge.dataStore.scenarioStore.put('searchTextInput' , searchTextInput);
} );
step('<searchText> で検索する' , async (searchText) => {
const searchTextInput = gauge.dataStore.scenarioStore.get('searchTextInput' );
await _.typeText(searchTextInput, searchText);
await _.pressKey('enter' );
} );
step('検索結果ページのタイトルが <title> であることを確認する' , async (title) => {
const titleElement = Selector('title' ).with ({ boundTestRun: _ } );
const pageTitle = await titleElement.innerText;
gauge.message(`検索結果ページのタイトル: ${ pageTitle} `);
await _.expect(pageTitle).eql(title);
} );
TestCafeでは通常 fixture
と test
で記述していきますが、Gauge+TestCafeでは、実行時にGaugeのシナリオがTestCafeのfixtureに変換されるようです。
前回Java で記述した部分をそのままJavaScript に置き換えただけなので、TestCafeの記述としては洗練されていないですが、この状態で yarn test
でテストの実行ができました。
感想
GaugeとTestCafeの組み合わせは、あまり良くはない印象です。
感じたデメリット
GaugeのJavaScript によるテスト実装では、ステップを step_implementation.js
にしか記述できないようです。私の調査不足かもしれませんが、ドキュメントをざっと読んだ限り、変更方法などは見つけられませんでした。
Gauge+TestCafeのサンプルプロジェクトでも、 step_implementation.js
から test_controller_holder.js
をimportしているため、実装を分割することは可能ですが、テストのステップをすべて単一ファイルに記述することになると、管理が煩雑になりそうです。
また、TestCafeの複数ブラウザによるテストや、並列テスト実行 が活かせなくなりました。こちらはTestCafeのメリットを打ち消してしまっています。
TestCafe単体でできたことが、Gaugeと組み合わせたことでできなくなるのであれば、相性が悪いと言って差し支えないかと思います。
Gauge+Java との使用感の違い
Gauge+Java では複数ファイルにステップ記述が可能なため、そちらと比較するとGauge+JavaScript は使い勝手が悪く感じました。
GaugeのData Storeに相当するctxがTestControllerに用意されていたりと 、TestCafe自体が高機能ということもあり、Java と組み合わせたときほど利便性の向上も感じませんでした。
TestCafeでBDDするための代替手段
TestCafeをGaugeと組み合わせるのは難しそうなので、Cucumberなど他のツールとの組み合わせが可能か調べてみました。
3年ほどOpenされているTestCafeのissue で、CucumberとTestCafeの統合についての要望が上がっており、そこからたどったissueの Cucumber Integration with Testcafe removed from roadmap? にて、Cucumber Integration
がロードマップから削除されたこと、および gherkin-testcafe の使用が推奨されていました。
gherkin-testcafe
を用いれば、Gherkin構文でTestCafeのテスト記述および実行ができるため、現時点ではこれを使うのがTestCafe+BDDには最適なようです。
実運用ではPage Objectとしてテスト対象のページをクラス化し、それをGherkinで記述したテスト仕様クラスから操作するのがいいかと思います。
総括
Gauge+Java ではかなりのメリットを感じられたのですが、Gauge+TestCafeではデメリットが目立つ結果となりました。
TestCafe自体の有用性は確認でき、またPage Object Patternによる記述ができることも確認できたため、今後はPage Object Patternによる実装や、 gherkin-testcafe
との組み合わせの検証を行いたいと思います。
最後に
Holmesではエンジニア・デザイナーを募集しております。ご興味がある方はこちらからご連絡ください。
lab.holmescloud.com
lab.holmescloud.com