こんにちは。 テストオートメーショングループのおすしです。
自動テストのテスト結果を確認していると、手動テストなら「問題なし」と判断できるエラーが出ていることはありませんか?
テスト精度にブレがないのは非常に良い点なのですが、もう少し臨機応変にできないものか…と思ってしまいます。
例えば、アプリのデータ登録機能をテストする場合に、「登録した日時(yyyy/MM/DD hh:mm)が正しく表示されていること」という確認項目があるとします。
手動テストで確認する場合は、以下の流れで問題なく確認できます。
<手動テストの場合>
- アプリを操作してデータを登録する
- アプリ上のデータの登録日時が「2023/02/03 11:59」と表示されている
- PCの現在日時を見ると「2023/02/03 12:00(:01))」だった
- 2秒くらい前に登録操作をしたから、日時の表示は正しい!
(※数秒のズレが許容されるテストの場合)
ところが、自動テストの場合はそうはいきません。
<自動テストの場合>
- アプリを操作してデータを登録する
- アプリ上のデータの登録日時が「2023/02/03 11:59」と表示されている
- 現在日時を取得すると「2023/02/03 12:00」だった
- 一致しないので、日時の表示は間違っている!
日時の確認で安定して自動テストを動かすには、許容されるズレを含めた確認をする必要があります。
また、SaaSのテスト自動化ツールの多くは海外サーバー上で動作しています。そのため、自動テストで現在日時を取得すると、アプリで使用しているタイムゾーンと異なる日時を取得してしまう場合があります。
指定したタイムゾーンの現在日時を取得する必要があります。
今回はこの2つの課題をJavaScriptで解決したお話です。
以下の順番で解説していきます。
- 【課題1】テスト実行環境のローカルタイムがテスト対象のタイムゾーンと異なる
- 【課題2】1秒でもずれるとテストが失敗してしまう
実装シナリオ
ボタンを押した日時が記録されるWebアプリを例にして説明します。
テスト対象の画面仕様
・トレーニングを3個選択し、「実行しました!」ボタンをクリックするとその時刻が「最終実行日時」に登録される
・日時の表示は「yyyy/mm/dd hh:mm:ss」
テスト内容
操作:
1.トレーニングリストの「チェック」欄を3箇所ONにする
2.「実行しました!」のボタンをクリックする
確認内容:
チェックを入れたデータの「最終実行日時」が、ボタンをクリックした日時と一致していること
レコード時の問題点
可変の現在日時を確認する機能がないため、既存機能だけではテストが実装できません。
JavaScriptのコード
【課題1】テスト実行環境のローカルタイムがテスト対象のタイムゾーンと異なる
まずは手元のパソコンで現在日時を取得してみます。
ブラウザの開発ツールからコンソールウィンドウを開いて以下のJavaScriptコマンドを実行します。
Date();
<結果>
Thu Feb 16 2023 14:41:57 GMT+0900 (日本標準時)
同じコマンドを、SaaSの自動化ツール上で実行してみます。
<結果>
Thu Feb 16 2023 05:36:54 GMT+0000 (Coordinated Universal Time)
テスト自動化ツールの実行サーバーは世界標準時のようです。
Date()はローカルタイムを取得するため、実行したマシンの影響を受けます。
テスト対象の「筋トレアプリ」は常に日本標準時で日時を記録する仕様です。
そのため、テスト時も日本標準時の時間を取得する必要があります。
自動テストツールの実行環境が常に世界標準時とは限らないため、取得したローカルタイムを世界標準時に合わせた後、日本標準時に調整することにします。
/**
* 現在の日本標準時刻を返します。
* ローカルタイムにかかわらず常に日本標準時を返します。
* @returns{string} 日時
*/
function getJapanStandardTime() {
//現在日時を取得(1970 年 1 月 1 日 00:00:00 から経過したミリ秒数の形式)
const localDateAndTime_ms = Date.now();
//ローカルタイムと世界標準時の差を取得(ミリ秒数に合わせる)
const localTimezoneOffset_ms =
new Date().getTimezoneOffset() * 60 * 1000;
//日本標準時のオフセットを計算(ミリ秒数に合わせる)
const JAPAN_TIMEZONE = 9;
const JAPAN_TIMESONE_OFFSET_ms = JAPAN_TIMEZONE * 60 * 60 * 1000;
//世界標準時との差をなくしてから日本標準時にする
const utcDateTime = localDateAndTime_ms + localTimezoneOffset_ms;
const japanDateTime = utcDateTime + JAPAN_TIMESONE_OFFSET_ms;
return japanDatesAndTimes;
}
【課題2】1秒でもずれるとテストが失敗してしまう
秒数までの日時を確認する場合、アプリのデータ登録と現在日時の取得が1秒でもずれると一致しないのでテストが失敗します。
そこで、テスト時にずれても許容範囲内の日時を準備します。
引数「offset_sec」に渡した秒数が許容範囲になります。
/**
* 現在の日本標準時刻と、指定した秒数を±した時刻の3つを配列で返します。
* ローカルタイムにかかわらず常に日本標準時を返します。
* @param {number} offset_sec 許容範囲内とする秒数のズレ(秒)
* @returns{arry} 現在時刻-offset_sec、現在時刻、現在時刻+offset_secの配列
*/
function getJapanStandardTime(offset_sec) {
//現在日時を取得(1970 年 1 月 1 日 00:00:00 から経過したミリ秒数の形式)
const localDateAndTime_ms = Date.now();
//ローカルタイムと世界標準時の差を取得(ミリ秒数に合わせる)
const localTimezoneOffset_ms =
new Date().getTimezoneOffset() * 60 * 1000;
//日本標準時のオフセットを計算(ミリ秒数に合わせる)
const JAPAN_TIMEZONE = 9;
const JAPAN_TIMESONE_OFFSET_ms = JAPAN_TIMEZONE * 60 * 60 * 1000;
const offset_ms = offset_sec * 1000;
//世界標準時との差をなくしてから日本標準時にする
const utcDateTime = localDateAndTime_ms + localTimezoneOffset_ms;
const japanDateTime = utcDateTime + JAPAN_TIMESONE_OFFSET_ms;
const japanDatesAndTimes = [];
japanDatesAndTimes.push(new Date(japanDateTime - offset_ms));
japanDatesAndTimes.push(new Date(japanDateTime ));
japanDatesAndTimes.push(new Date(japanDateTime + offset_ms));
return japanDatesAndTimes;
}
<5を渡した場合の結果>
現在日時マイナス5秒、現在日時、現在日時プラス5秒の3つの日時が算出されます。
(3) [Thu Feb 16 2023 18:09:29 GMT+0900 (日本標準時), Thu Feb 16 2023 18:09:34 GMT+0900 (日本標準時), Thu Feb 16 2023 18:09:24 GMT+0900 (日本標準時)]
0:Thu Feb 16 2023 18:09:24 GMT+0900 (日本標準時) {}
1:Thu Feb 16 2023 18:09:29 GMT+0900 (日本標準時) {}
2:Thu Feb 16 2023 18:09:34 GMT+0900 (日本標準時) {}
次に、渡した日時が許容範囲内かを判定する処理を作成します。
Date.parse()は日付形式のテキストを渡すと、1970 年 1 月 1 日 00:00:00 から経過したミリ秒数の形式に変換してくれるメソッドです。
先程作成した「getJapanStandardTime」を中に入れています。
/**
* 引数で渡した日時が、現在日時の±指定秒数以内であるかを判定します。
* @param date {string} "yyyy/mm/dd hh:mm:ss"形式の日時
* @param offset_sec {number} 許容範囲内とする時間のズレ(秒)
* @author osushi
*/
function checkDateAndTimeAcceptable(date, offset_sec) {
//引数チェック
if (!offset_sec) {
throw new Error("2番目の引数が入力されていません");
} else if (typeof(offset_sec) !== "number"){
throw new Error("offset_secは数値を入力してください")
}
//テストで使用する日時を取得
const dates = getJapanStandardTime(offset_sec);
//テスト対象の日時、比較対象の日時をミリ秒表記にする
const dateAndTimeMinus = Date.parse(dates[0]);
const dateAndTimeNow = Date.parse(date);
const dateAndTimePlus = Date.parse(dates[2]);
if (dateAndTimeMinus < dateAndTimeNow && dateAndTimeNow < dateAndTimePlus) {
console.log("日時データは許容範囲内です");
} else {
console.log("dateAndTimeMinus : ",dateAndTimeMinus);
console.log("dateAndTimeNow : ",dateAndTimeNow);
console.log("dateAndTimePlus : ",dateAndTimePlus);
throw new Error("日時データが許容範囲内ではありません");
}
/**
* 現在の日本標準時刻と、指定した秒数を±した時刻の3つを配列で返します。
* ローカルタイムにかかわらず常に日本標準時を返します。
* @param {number} offset_sec 許容範囲内とする秒数のズレ(秒)
* @returns{arry} 現在時刻-offset_sec、現在時刻、現在時刻+offset_secの配列
*/
function getJapanStandardTime(offset_sec) {
//現在日時を取得(1970 年 1 月 1 日 00:00:00 から経過したミリ秒数の形式)
const localDateAndTime_ms = Date.now();
//ローカルタイムと世界標準時の差を取得(ミリ秒数に合わせる)
const localTimezoneOffset_ms =
new Date().getTimezoneOffset() * 60 * 1000;
//日本標準時のオフセットを計算(ミリ秒数に合わせる)
const JAPAN_TIMEZONE = 9;
const JAPAN_TIMESONE_OFFSET_ms = JAPAN_TIMEZONE * 60 * 60 * 1000;
const offset_ms = offset_sec * 1000;
//世界標準時との差をなくしてから日本標準時にする
const utcDateTime = localDateAndTime_ms + localTimezoneOffset_ms;
const japanDateTime = utcDateTime + JAPAN_TIMESONE_OFFSET_ms;
const japanDatesAndTimes = [];
japanDatesAndTimes.push(new Date(japanDateTime - offset_ms));
japanDatesAndTimes.push(new Date(japanDateTime ));
japanDatesAndTimes.push(new Date(japanDateTime + offset_ms));
return japanDatesAndTimes;
}
}
テスト実装
あとは「最終実行日時」のテキストを取得し、作成した関数に渡すだけです。
<テストの流れ>
- トレーニングリストの「チェック」欄を3箇所ONにする
- 「実行しました!」のボタンをクリックする
- ページから「最終実行日時」を取得する※1
- 「checkDateAndTimeAcceptable」に手順3のテキストと許容範囲とする秒数を渡して確認する
※1 ページ内の特定のテキストを取得するJavaScriptスニペットは、Autifyの公式ページで紹介されています。
おわりに
今回は以下の課題と解決案を解説しました。
【課題1】コードを実行したローカル環境の現在日時を取得してしまう
→ 解決策:オフセットを利用して現在日時を取得したいタイムゾーンに調整する
【課題2】1秒でもずれるとテストが失敗してしまう
→ 解決策:ズレの許容範囲を指定して、その範囲内かを判定する
将来、優秀なテスターのようにテストを実行してくれるAIが開発されたら、自動的に許容範囲かを判断してテストできるようになるかもしれません。
テストはすべてAIにおまかせして、実装にかける工数を増やせるようになるといいですね。