o1(OpenAI o1)はGPTの冠が外れたLLMのモデルです。
o1は思考時間をとることにより、4oよりも高度な推論が可能となっているモデルです。
数学やコーディングのテストにおいて4oのスコアを大きく引き離しています。
そのo1-previewを用いてサンプルアプリのテスト観点を出してもらい、私が出したテスト観点と比較を行ってみました。
- 話を進める前にテストについて大事なこと
- 結論から
- お題と僕が出したテスト観点
- o1にテスト観点を出してもらう
- o1が出したテスト観点を確認
- 私が出したテスト観点と比較
- o1ではどういったテスト観点が出せなかったか
- 私はどういった観点が出せなかったか
- o1が出した観点でテスト項目を作ってもらった結果
- これらの結果からo1のテストの活用について
- o1を使ったこんなテスト作成の流れはどうだろう?
話を進める前にテストについて大事なこと
テストにおいて仕様通り動くかのチェックはとても大切です。
ですが、それだけではテストは足りません。
仕様には書いていない考慮漏れで問題が発生する、端末の画面サイズで問題が発生する、他のシステムと連携で問題が発生してしまうといったことがあります。
数年IT界隈にいる人でしたら、そういったところで本番障害に遭遇して苦労した経験があるかと思います。
仕様通り動くかのチェックは最低限のテスト活動であり、加えて仕様外に目を向け「発想」する必要があります。
テストとは、エラーをみつけるつもりでプログラムを実行する過程である
by Glenford J. Myers (ソフトウェア・テストの技法 第2版)
なぜこの話をしたかというと、これから話すo1の結果に関係があるからです。
結論から
- 結果
- o1活用の考え
- o1にベースとなるテスト観点を出してもらって、人間が暗黙知、経験からテスト観点を追加しテストを作っていく
- 仕様確認である動作チェック部分はo1で作ってしまいスモークテストとする。並行して人間が不足観点部分のテストを作る(o1と人間の分業)
お題と僕が出したテスト観点
この仕様書を使って、私もテスト観点を出してみました。
↓結果
o1にテスト観点を出してもらう
与えたプロンプトは以下です。
このアプリで何をテストしたらいいかのテスト観点をMindmapで出してください。Mindmapはmermaid形式で出力してください。
不明な情報は私に質問を返してください。割り勘アプリを開発します。
飲み会の時などに使いたくなるものです。
「合計金額」と「割り勘したい人数」から一人当たりの金額と不足金額(割り切れなかった分のお金)を出します。
「金額を固定したい人数」は、例えば遅れてきた人は1000円ね、としたい場合に使用します。合計金額……半角6桁。合計金額。最低金額は0円
割り勘したい人数 ……半角2桁。割る人数。最低1人
金額を固定したい人数……半角2桁。割り勘に含めず固定した金額を払う人数。未入力の場合0として扱う
固定する金額……半角6桁。固定した金額を払う人が払う金額。金額を固定したい人数が未入力の時は非アクティブ。計算ボタン……押すと一人当たりの金額と不足額を計算する
一人の金額 ……半角6桁。割り勘した一人当たりの金額。カンマ区切り
不足金額…… 半角6桁。割り勘したときのあまりの金額。
ちなみにmermaid記法はマークダウンでマインドマップやフローチャート、シーケンス図などが書ける方法です。AIでテスト観点を列挙するだけならマインドマップにする必要はないなといまさら思っています。
結果は以下です。
mindmap
根*1
入力値の検証
合計金額
- 最小値 (0円)
- 最大値 (999,999円)
- 桁数 (半角数字6桁)
- 無効な入力
- 負の数
- 文字列
- 特殊文字
割り勘したい人数
- 最小値 (1人)
- 最大値 (99人)
- 桁数 (半角数字2桁)
- 無効な入力
- 負の数
- 0
- 文字列
- 特殊文字
金額を固定したい人数
- 未入力時は0として扱う
- 桁数 (半角数字2桁)
- 無効な入力
- 負の数
- 文字列
- 特殊文字
固定する金額
- 非アクティブ条件
- 金額を固定したい人数が未入力時
- 桁数 (半角数字6桁)
- 無効な入力
- 負の数
- 文字列
- 特殊文字
機能テスト
計算ボタン
- 正しい計算結果
- 一人当たりの金額
- 不足金額
- 固定金額の人がいる場合の計算
- 入力が無効な場合の動作
- エラーメッセージの表示
- 計算を行わない
フィールドの状態
- 非アクティブ条件
- 金額を固定したい人数が未入力時、固定する金額は非アクティブ
ユーザーインターフェース
表示フォーマット
- 一人当たりの金額
- カンマ区切り
- 不足金額
- カンマ区切り
エラーメッセージ
- 無効な入力時の適切な表示
- フォーカスの移動
ユーザビリティ
- 使いやすさ
- 入力しやすさ
- ボタンやフィールドのレイアウト
パフォーマンス
- 計算のレスポンスタイム
- 大量入力時の動作
セキュリティ
- 不正入力への耐性
- データの保護
互換性
- 異なるデバイスでの動作
- 異なるブラウザでの表示
mermaid記法とは少し違いましたが、テスト観点としては良さそうなものが出力されました。
生成のたびにパフォーマンスやユーザビリティなどが抜けたりなど、結果は都度変わります。
フォーカスを変えながら(機能に注目、~性に注目など)何度か観点を出してマージしてもよいかもしれません。今回はまとめてテスト観点を出力させた状態で進めます。
o1が出したテスト観点を確認
半角6桁、という内容から999,999円の境界値を出すことができています。
ただ1,000,000円の境界値は出ません。
無効な入力も出してくれるのはGoodです。試したほうがよさそうな主要なカテゴリは出ています。
割り勘したい人数は1人からなので、無効の値に0が入っているのはGoodです。
固定する金額も非アクティブの条件は仕様に明記しているので出ています。
動作チェックであればアクティブである条件も見ておきたいところです。
固定人数を入れた正常系の処理時に通るから不要である、という考え方もできそうです。
機能テストのカテゴリは、イレギュラーなパターンは含まれていません。
イレギュラーなパターンは、同値分割から考えられそうな無効な値などではなく、固定した人数のお金が合計金額を上回ってしまう場合はどうなるかといった、想像して「こういう問題が起きそうだな」というパターンです。
ユーザビリティやパフォーマンス、セキュリティ、互換性の観点が入ってきたのはExcellentです。
このアプリにどこまで求めるかによって剪定する観点になるかと思いますが、まずはこれらが出せていることが素晴らしいです。
私が出したテスト観点と比較
o1が出したテスト観点と私が出したテスト観点をマージしたものが以下です。
記載した言葉の意味は以下です。
- OK……私もo1も双方が出した観点
- ADD……私が出したが、o1が出していない観点
- None……私が出せなかったが、o1が出した観点
```mermaidmindmaproot*2入力値の検証合計金額最小値 (0円) OK最大値 (999,999円) OK桁数 (半角数字6桁) OK無効な入力負の数 OK文字列 OK特殊文字 OKe ADD小数 ADDカンマ ADD01みたいな数字 ADD無(null) ADD-0を入れたらどうなる? ADD攻撃クソデカ数字いれたら壊れない? ADD割り勘したい人数最小値 (1人) OK最大値 (99人) OK桁数 (半角数字2桁) OK無効な入力負の数 OK0 OK文字列 OK特殊文字 OK攻撃割り勘したい人数が合計金額を超えた場合 ADD計算割り切れる場合 ADD割り切れない場合 ADD金額を固定したい人数未入力時は0として扱う OK桁数 (半角数字2桁) OK無効な入力負の数 OK文字列 OK特殊文字 OK固定する金額非アクティブ条件金額を固定したい人数が未入力時 OKアクティブ条件固定したい人数入力済み ADD固定したい人数が無効の値だったらどうなるの? ADD桁数 (半角数字6桁) OK無効な入力負の数 OK文字列 OK特殊文字 OK計算ボタン攻撃全部何も入力していない状態でクリック ADD入力ボックスでエンターで計算される?されない? ADD連打 ADD何度も繰り返して計算しても大丈夫? ADD機能テスト計算ボタン正しい計算結果一人当たりの金額 OK不足金額 OK固定金額の人がいる場合の計算 OK固定のみ合計金額アリ ADD合計金額なし ADD入力が無効な場合の動作エラーメッセージの表示 OK計算を行わない Noneフィールドの状態非アクティブ条件金額を固定したい人数が未入力時、固定する金額は非アクティブ OKバグを出すためのテスト人数を入れてアクティブにして入力後に人数を抜いて非アクティブにしたらどうなるの? ADD合計金額を固定する金額 * 人数が合計金額を超えたらどうなるの? ADD合計金額を固定する金額 * 人数は超えないが、割り勘したい人数で割った結果、合計金額が1円を切る ADD表示フォーマット一人当たりの金額カンマ区切り OK不足金額カンマ区切り OKエラーメッセージ無効な入力時の適切な表示 OKフォーカスの移動 None使いやすさ None入力しやすさ Noneボタンやフィールドのレイアウト Noneパフォーマンス計算のレスポンスタイム OK大量入力時の動作 Noneセキュリティ不正入力への耐性 Noneデータの保護 None互換性異なるデバイスでの動作 OK異なるブラウザでの表示 OK画面サイズ普通 ADD小さい ADDブラウザリロード ADD戻る ADD```
集計結果は以下です。
- OK……34件
- ADD……25件
- None……8件
- OK + ADD + None(つまり全件) = 67件
- OK + None(つまりo1が出した観点)……42件(62.7%)
- OK + ADD(つまり私が出した観点)……59件(88.1%)
o1ではどういったテスト観点が出せなかったか
主に「この辺どうなるんだろう?」という仕様に載っていないところは出せません。
「発想」はまだ人間の領域のようです。
こういった部分は実務では企画や聞いて明確化してもらう、実際に試してみてどうなるか確認する場所となります。
お金の計算ですと、切り上げ、切り捨てどちらの処理かで支払う額が変わってきます。
割り勘程度のアプリですと大したことありませんが、大きなお金を扱うシステムだと要注意です。端数をどうにかしていた、という悪事を聞いたことがあります。
もしかしたら割り勘でも1円の誤差で怒る人だっているかもしれません。
意地悪テストも出せません。
例えば今回であれば、固定人数が未入力だと固定金額は非アクティブです。
けれど固定人数を入力し固定金額をアクティブにした上で固定人数を抜いてしまったらどうなるのでしょうか?
表示だけがおかしくなるならいいですが、計算結果に何かしら影響があると困ります。
「そういう処理はしていない」という人もいますが、いざ試してみると「あれ!?なんでそうなった!?」があったりするものです。
あとは、例えば固定した人数の金額が合計を超えてしまう、超えてしまわなくても計算結果割り勘の結果が1円を切ってしまったらどうなるのだろう?といった部分です。
テスト設計レベル(パターン出しといったところ)にはなってしまいますが、「普通の割り勘のみ使うパターン」「普通の割り勘と固定を使うパターン」があるのならば、機械的に考えると「固定のみのパターン」と「何も入力しないパターン」が考えられます。
実際にテストを作っていく際は「本当にそのテスト観点はテストしたほうがいいのか」と優先度を考えて、テスト観点を「剪定」する必要があります(テスト工数は有限のため)。私が出した観点だと「連打」も入っていたりしますが、何か登録が発生しないのであれば剪定してしまうと思います。
私はどういった観点が出せなかったか
ユーザビリティ、セキュリティといったところが出せていませんでした。
セキュリティであればweb系はXSSはやっておいてよいでしょう。
あとサーバーを介すようなアプリだった場合はリクエスト数による負荷テストも考えられるかもしれません。
o1が出した観点でテスト項目を作ってもらった結果
せっかくなのでテスト項目まで作ってもらいました。
"項目番号","大項目","中項目","小項目","前提条件","テスト手順","期待結果"
"TC001","入力値の検証","合計金額","最小値","アプリが起動している","合計金額に0を入力する","エラーなく受け付ける"
"TC002","入力値の検証","合計金額","最大値","アプリが起動している","合計金額に999999を入力する","エラーなく受け付ける"
"TC003","入力値の検証","合計金額","最大値超過","アプリが起動している","合計金額に1000000を入力する","エラーメッセージを表示する:「合計金額は最大999,999円までです」"
"TC004","入力値の検証","合計金額","負の数入力","アプリが起動している","合計金額に-1を入力する","エラーメッセージを表示する:「合計金額は0円以上で入力してください」"
"TC005","入力値の検証","合計金額","文字列入力","アプリが起動している","合計金額に文字列「abc」を入力する","エラーメッセージを表示する:「合計金額は半角数字で入力してください」"
"TC006","入力値の検証","合計金額","特殊文字入力","アプリが起動している","合計金額に特殊文字「!@#」を入力する","エラーメッセージを表示する:「合計金額は半角数字で入力してください」"
"TC007","入力値の検証","合計金額","桁数超過","アプリが起動している","合計金額に7桁の数字「1000000」を入力する","エラーメッセージを表示する:「合計金額は6桁以内で入力してください」"
"TC008","入力値の検証","割り勘したい人数","最小値","アプリが起動している","割り勘したい人数に1を入力する","エラーなく受け付ける"
"TC009","入力値の検証","割り勘したい人数","最大値","アプリが起動している","割り勘したい人数に99を入力する","エラーなく受け付ける"
"TC010","入力値の検証","割り勘したい人数","最大値超過","アプリが起動している","割り勘したい人数に100を入力する","エラーメッセージを表示する:「割り勘人数は最大99人までです」"
"TC011","入力値の検証","割り勘したい人数","負の数入力","アプリが起動している","割り勘したい人数に-1を入力する","エラーメッセージを表示する:「割り勘人数は1以上で入力してください」"
"TC012","入力値の検証","割り勘したい人数","文字列入力","アプリが起動している","割り勘したい人数に文字列「abc」を入力する","エラーメッセージを表示する:「割り勘人数は半角数字で入力してください」"
"TC013","入力値の検証","割り勘したい人数","特殊文字入力","アプリが起動している","割り勘したい人数に特殊文字「!@#」を入力する","エラーメッセージを表示する:「割り勘人数は半角数字で入力してください」"
"TC014","入力値の検証","割り勘したい人数","0入力","アプリが起動している","割り勘したい人数に0を入力する","エラーメッセージを表示する:「割り勘人数は1以上で入力してください」"
"TC015","入力値の検証","金額を固定したい人数","未入力時の扱い","アプリが起動している","金額を固定したい人数を未入力にする","システムは0として扱う"
"TC016","入力値の検証","金額を固定したい人数","負の数入力","アプリが起動している","金額を固定したい人数に-1を入力する","エラーメッセージを表示する:「金額を固定したい人数は0以上で入力してください」"
"TC017","入力値の検証","金額を固定したい人数","文字列入力","アプリが起動している","金額を固定したい人数に文字列「abc」を入力する","エラーメッセージを表示する:「金額を固定したい人数は半角数字で入力してください」"
"TC018","入力値の検証","金額を固定したい人数","特殊文字入力","アプリが起動している","金額を固定したい人数に特殊文字「!@#」を入力する","エラーメッセージを表示する:「金額を固定したい人数は半角数字で入力してください」"
"TC019","入力値の検証","固定する金額","未入力時の扱い","金額を固定したい人数が入力されている","固定する金額を未入力にする","エラーメッセージを表示する:「固定する金額を入力してください」"
"TC020","入力値の検証","固定する金額","負の数入力","金額を固定したい人数が入力されている","固定する金額に-1000を入力する","エラーメッセージを表示する:「固定する金額は0円以上で入力してください」"
"TC021","入力値の検証","固定する金額","文字列入力","金額を固定したい人数が入力されている","固定する金額に文字列「abc」を入力する","エラーメッセージを表示する:「固定する金額は半角数字で入力してください」"
"TC022","入力値の検証","固定する金額","特殊文字入力","金額を固定したい人数が入力されている","固定する金額に特殊文字「!@#」を入力する","エラーメッセージを表示する:「固定する金額は半角数字で入力してください」"
"TC023","機能テスト","計算ボタン","正しい計算結果","正しい入力値が全て入力されている","計算ボタンを押す","正しい一人当たりの金額と不足金額が表示される"
"TC024","機能テスト","計算ボタン","固定金額の考慮","固定金額の人がいる設定で正しい入力値が全て入力されている","計算ボタンを押す","固定金額の人を除いた割り勘金額と不足金額が正しく計算される"
"TC025","機能テスト","計算ボタン","無効な入力時の動作","合計金額に無効な値が入力されている","計算ボタンを押す","エラーメッセージが表示され、計算は行われない"
"TC026","機能テスト","計算ボタン","無効な入力時の動作","割り勘したい人数に無効な値が入力されている","計算ボタンを押す","エラーメッセージが表示され、計算は行われない"
"TC027","機能テスト","フィールドの状態","非アクティブ条件","金額を固定したい人数が未入力または0の時","固定する金額フィールドが非アクティブであることを確認する","固定する金額フィールドが入力不可である"
"TC028","機能テスト","フィールドの状態","アクティブ条件","金額を固定したい人数が1以上の時","固定する金額フィールドがアクティブであることを確認する","固定する金額フィールドが入力可能である"
"TC029","ユーザーインターフェース","表示フォーマット","一人当たりの金額の表示","計算結果が表示された後","一人当たりの金額がカンマ区切りで表示されていることを確認する","金額がカンマ区切りで正しく表示されている"
"TC030","ユーザーインターフェース","表示フォーマット","不足金額の表示","計算結果が表示された後","不足金額がカンマ区切りで表示されていることを確認する","金額がカンマ区切りで正しく表示されている"
"TC031","ユーザーインターフェース","エラーメッセージ","適切な表示","無効な入力値がある状態","計算ボタンを押す","対応するエラーメッセージが表示される"
"TC032","ユーザーインターフェース","エラーメッセージ","フォーカスの移動","エラーメッセージが表示された後","エラーのある入力フィールドにフォーカスが移動することを確認する","エラーのある入力フィールドにフォーカスが移動する"
"TC033","ユーザビリティ","使いやすさ","ボタン配置","アプリが起動している","ボタンやフィールドのレイアウトを確認する","直感的で使いやすい配置になっている"
"TC034","ユーザビリティ","入力しやすさ","キーボード操作","アプリが起動している","タブキーで入力フィールド間を移動する","入力フィールド間をスムーズに移動できる"
"TC035","パフォーマンス","計算のレスポンスタイム","正しい入力値が全て入力されている","計算ボタンを押す","計算結果が即座に表示される(レスポンスが速い)"
"TC036","パフォーマンス","大量入力時の動作","合計金額に999999を入力する","計算ボタンを押す","システムが遅延なく応答する"
"TC037","セキュリティ","不正入力への耐性","スクリプト入力","入力フィールドに「<script>alert('test')</script>」を入力する","スクリプトが実行されず、エラーメッセージが表示される"
"TC038","セキュリティ","データの保護","個人情報の入力","入力フィールドに個人情報を入力する","データが外部に漏洩しない(ただし、個人情報は入力しない想定)"
"TC039","互換性","デバイス間の動作","スマートフォンでの操作","スマートフォンでアプリを起動し、操作する","正しく表示・動作する"
"TC040","互換性","デバイス間の動作","タブレットでの操作","タブレットでアプリを起動し、操作する","正しく表示・動作する"
"TC041","互換性","デバイス間の動作","PCでの操作","PCでアプリを起動し、操作する","正しく表示・動作する"
"TC042","互換性","ブラウザ間の動作","Chromeでの操作","Chromeでアプリを起動し、操作する","正しく表示・動作する"
"TC043","互換性","ブラウザ間の動作","Firefoxでの操作","Firefoxでアプリを起動し、操作する","正しく表示・動作する"
"TC044","互換性","ブラウザ間の動作","Safariでの操作","Safariでアプリを起動し、操作する","正しく表示・動作する"
"TC045","入力値の検証","全角入力の対応","全角数字入力","アプリが起動している","合計金額に全角数字「123456」を入力する","エラーメッセージを表示する:「半角数字で入力してください」"
"TC046","入力値の検証","合計金額","全角文字入力","アプリが起動している","合計金額に全角文字「あいう」を入力する","エラーメッセージを表示する:「合計金額は半角数字で入力してください」"
"TC047","機能テスト","計算ボタン","合計不一致の検証","固定する金額が合計金額を超える場合","計算ボタンを押す","エラーメッセージを表示する:「固定金額は合計金額以下で入力してください」"
"TC048","機能テスト","計算ボタン","人数不一致の検証","割り勘したい人数と金額を固定したい人数の合計が不合理な場合","計算ボタンを押す","エラーメッセージを表示する:「人数の合計が正しくありません」"
"TC049","入力値の検証","固定する金額","合計金額超過","金額を固定したい人数が入力されている","固定する金額に合計金額+1を入力する","エラーメッセージを表示する:「固定する金額は合計金額以下で入力してください」"
"TC050","ユーザビリティ","エラーメッセージ","内容の明確さ","無効な入力値がある状態","エラーメッセージの内容を確認する","エラー原因が明確に伝わるメッセージが表示されている"
……見づらいですね。
テストクラスタからは怒られる大中小項目で出してもらいました。
最低限動作しているか仕様をなぞるテストとしては良しに見えています。
(エラーメッセージは勝手に作られてしまっているけど)
僕ならスモークテストでこの項目を通す、は戦術として悪い手ではないと考えます。
このテスト項目を通せば、このアプリのそれこそ60%程度はチェックができそうです。
文字列だけ細かい、互換性のテストはザックリ、なども見て取れますが、ここは観点ごとに区切って生成しながらテストを詳細化するという手もとれそうだと感じます。
これらの結果からo1のテストの活用について
細かいテスト観点が出せないからo1は使えないとするのはあまりに0/1思考すぎます。
このサンプルアプリでいえば60%程度は出せています。
仕様に書かれている場所はCPM法(仕様書をコピペしてテスト項目とする)より出せています。
o1にベースとなるテスト観点を出してもらい、人間がそれらをもとにこれまでの経験、プロジェクトの暗黙知から「発想」してテスト観点を追加するのは手です。
私が出せなかった観点も含まれていましたので、ベースとすることでテスト観点の補間もできるでしょう。
また、o1が出したテスト観点から生成されたテスト項目はスモークテストレベルには使えそうに見えています。
なので、まずはテスト項目を出してしまって、開発側に「この項目は通るようにお願いします」というようにTDD的に使うこともできるかもしれません。
残念ながら仕様をなぞるチェックで終始している場所であれば、o1にしてしまってもよいかもしれません。(もちろんテスト不足のリスクを許容するならば)
o1を使ったこんなテスト作成の流れはどうだろう?
今後実務でも試してみようと思っていますが、こんな流れはどうだろうかと思っています。
- o1に仕様を食わせて複数回テスト観点を出す
- 全ての結果をマージする (AIを使ってでも手動でも)
- 人間がこれまで経験したバグや、気になること、プロジェクトの暗黙知から観点を追加する
- テスト観点に優先度をつけ、不要なテスト観点は剪定する
- それぞれの観点ごとにパターン出しを行う(人がテスト技法を使っても、o1にやってもらうでも)
- テスト観点及び各パターンをo1 に渡してテスト観点ごとにテスト項目化する