みなさんこんにちは、SET(Software Engineer in Test)のRueyです。
弊SETチームの活動として、自動テストの実施依頼を受けています。
最近は大規模な範囲にページ内の特定な要素を追加する施策の自動テストを対応しました。 テスト内容はURLへアクセスして特定のタグがあるかを確認することなので、データ駆動型テストで対応しました。
開発チームの実装後、こちらからデータ駆動型テストを実施し、結果を報告する形になります。
テスト結果報告後に開発チームはバグ修正を行い、すべてのテストケースがPassするまで「再テスト➡︎再修正」の繰り返しを行いました。
すべてのテストを実行すると実行時間がかかりフィードバックが遅れるため、前回失敗したテストケースのみを再実行したいです。 なので、そのような仕組みがあった方が対応しやすいと考えました。
今回の記事では、データ駆動型テストにおいて失敗したテストケースのみを再実行できる仕組みを紹介したいと思います。
目次
データ駆動型テスト(Data-driven testing)とは?
仕組みを説明する前に、まずはデータ駆動型テストについて少し紹介します。
スクリプト記述技法のひとつ。テストスクリプトの実行に必要なテストデータおよび期待結果を含んだデータファイルを使う。
と定義しています。
今回の施策におけるテストでは、2000個程度のURLへアクセスして各ページ内に同じような検証を行います。 なので、テスト実行スクリプトを一つ用意して、後は大量のテストデータに記載しているURLと期待値を利用し、「URLへ遷移➡︎期待値検証」のループで対応します。まさしくデータ駆動型テストになっています。
データ駆動型テストのポイントとして、検証の部分を共通化することが大事です。テストケース数は大量になるので、全て同じ検証関数が使うことができれば実装が楽になります。
データ駆動型テストの例
ここはURLごとにページHTMLのtitleタグの内容を確認する例を紹介します。
テストデータ
JSON式でURLとtitleタグの期待値が入っています。
sample-data.json
[ { "url": "https://devexpress.github.io/testcafe/example", "expectedTitle": "TestCafe Example Page" }, { "url": "https://testcafe.io", "expectedTitle": "Cross-Browser End-to-End Testing Framework | TestСafe" }, { "url": "https://testcafe.io/documentation/402632/reference", "expectedTitle": "Reference | Docs" } ]
サンプルコード
TestCafeというテストフレームワークで書いています。データ駆動型に対応していますので、簡単に実装ができます。
data-driven.js
import { Selector } from 'testcafe'; const dataSet = require('./sample-data.json'); fixture `Data-Driven Tests` dataSet.forEach(data => { test(`Testing for '${data.url}'`, async t => { await t .navigateTo(data.url) .expect(Selector('title').textContent).eql(data.expectedTitle); }); });
シンプルなコードでsample-data.jsonにある3つのデータをループして確認することができます。 TestCafe公式サイトの各URLへアクセスし、ページタイトルにあるテキストとJSONデータにある期待値が一致しているかを検証します。
どのような再実行の仕組みが必要か?
上記の例では3ケースしかないですが、今回の施策で実施したテストは2000ケースほどありました。 そして、一回目のテストでは200ケースほど失敗しました。
この結果を開発チームに報告し、開発チームが再修正を行った後、前回失敗した200ケースのみを再実行することになりました。
TestCafeだと、テストケース名を指定して実行する機能がありますが、200ケースを直接指定しないといけないのでかなり大変な作業になります。
このような場合に「失敗したテストケースのみを再実行できる仕組み」が必要です。
※ 本記事では失敗したテストケースのみの再実行の説明なので特に書いていませんが、バグ修正後には全てのテストケースが通るかを確認すべきです。
失敗したテストケースのみを再実行できる仕組み
テストフレームワークによっては、失敗したテストケースをあらかじめ設定した条件に沿ってその場で再実行する機能があります。 (TestcafeだとQuarantine mode)
ただし、今回の施策のように「開発チームが修正➡︎再テスト」を繰り返すようなパターンでは、この機能はそぐわないです。
このようなパターンのことを、ここでは不連続のテスト再実行と呼ぶことにします。
不連続のテスト再実行を実現するためには、前回の実行結果の記録が必要です。 再実行の際に記録を確認することで、前回失敗したケースのみ実行することが出来ます。
不連続のテスト再実行を実現する仕組みの例
今回はJSONのデータに前回のテスト結果を記録する部分を加えて、不連続のテスト再実行を実現する例を紹介します。
テストデータ
JSONデータは状態記録用の「passed」を追加します。初期値はfalseを設定します。
sample-data.json
[ { "url": "https://devexpress.github.io/testcafe/example", "expectedTitle": "TestCafe Example Page", "passed": false }, { "url": "https://testcafe.io", "expectedTitle": "Cross-Browser End-to-End Testing Framework | TestСafe", "passed": false }, { "url": "https://testcafe.io/documentation/402632/reference", "expectedTitle": "Reference | Docs", "passed": false } ]
サンプルコード
サンプルコードは実行の前にテストケースの実行状態を確認して、if文で実行もしくは実行しないを判断します。 また最後は実行成功時に状態をJSONファイルに状態を更新します。
data-driven.js
import { Selector } from 'testcafe'; const dataSet = require('./sample-data.json'); const fs = require('fs'); fixture `Data-Driven Tests` .after( async t => { fs.writeFileSync('./sample-data.json', JSON.stringify(dataSet,null, 2)); }); dataSet.forEach(data => { if(!data.passed){ test(`Testing for '${data.url}'`, async t => { await t .navigateTo(data.url) .expect(Selector('title').textContent).eql(data.expectedTitle); data.passed=true; }); }
これでテストフレームワークに不連続のテスト再実行の機能がなくでも、 テストデータに前回の実行結果を追加することにより、失敗したケースだけを再実行できる仕組みを簡単に実現できます。
最後に
この再実行できる仕組みを利用することで、修正後のデータ駆動型テストを簡単に行うことができました。
再実行したいテストケースの直接指定の大量な作業から解放できました。 ケース数が非常に多いデータ駆動型テストでの不連続のテスト再実行が必要な時に、この仕組みはとても役に立ちます。
もしみなさんも同じようなデータ駆動型テストを実施する機会があれば、この仕組みが参考になれば幸いです。
今回のサンプルで紹介したTestCafeには不連続のテスト再実行の仕組みがないですが、他のテストフレームワークにはあるかもしれません。 そのテストフレームワークを直接利用してもいいと思います。
最後は宣伝ですが、弊社製のBuckyにも不連続のテスト再実行の機能がありますので、ぜひご検討ください!
以上、ありがとうございました!