テストケースの作り方|送料判定の例で学ぶ条件・期待結果・実行記録
※本記事にはPRを含む場合があります。
こんにちは。『脱会社員』脱サラを応援し続けるブログ、運営者の『なかびー』です。
テストケースを作ろうとして、入力欄や期待結果の欄だけを用意したものの、「具体的に何を試せばよいのか」で手が止まることはありませんか。小さなプログラムでも、いつも使う数値を一つ入れただけでは、金額の境目や条件の重なりにある間違いを見落とします。
作る順番は、ルールを読める形にする、入力を同じ扱いのまとまりに分ける、境目を選ぶ、複数条件を組み合わせる、期待値と実際値を比べる、の順です。この記事では一つの架空の送料判定を使い、6要件から30ケースを選びます。「数を増やす」よりも、各ケースがどの間違いを見つけるためにあるかを説明できることを目指しましょう。
副業で小規模なプログラム制作や検証補助を考えている人も、まずは顧客情報を使わない小さな教材で練習できます。本文の金額、地域区分、送料ルールはすべて説明用です。実在の店舗や配送会社の料金ではなく、実案件を担当した実績の紹介でもありません。税、クーポン、注文保存、決済は扱いません。
この教材で確認したこと
学習用の計算関数で、基準版30件の通過、故意に入れた不具合5種類の検出、元の基準版に戻した30件の再通過を確認しました。実店舗・ブラウザー画面・外部API・決済・負荷・同時更新・アクセシビリティは未検証です。
テストケースは、入力・条件・期待結果を一組にして作る

仕様R05から、D03の入力「小計5,000円・非会員・通常地域・配送」と期待結果「送料0円・合計5,000円」へつなげる説明図です。実店舗の画面ではありません。
「送料が正しい」を、別の人も試せる条件へ変える
「送料が正しく計算されること」は、確認したい方向を示す言葉です。しかし、その一文だけでは何円の商品を買い、どこへ届け、会員なのかを決められません。人によって別の入力を使えば、両者が「確認した」と言っていても、見た条件が違います。
たとえばD01では、小計4,000円、配送、通常地域、非会員を入力します。期待する送料は600円、合計は4,600円です。入力値だけでなく、結果のどの項目を比べるかまで決めると、送料は合うが合計が間違う、といった不一致も拾えます。今回の結果は、状態を表すstatus、送料shipping、合計totalの3項目です。
ここでは、確認したい性質を「観点」、具体的な入力と手順と期待結果をまとめたものを「ケース」、動かして得た値を「実行結果」と呼び分けます。観点の例は「基本送料が無料になる境目」です。それを調べるケースの一つがB06で、実行結果として送料0円が返ったことを記録します。作る前から結果欄に合格を書いてしまうと、この区別が崩れます。
架空の送料判定教材v1.0の6要件です。本文を通して、この条件を変えずに使います。
※表は横にスクロールできます。右側の列まで確認してください。
| 要件 | 決めたルール |
|---|---|
| R01 | 小計は円単位の整数0〜100000。bool・文字列・小数・nullは受理しない。範囲外はE_AMOUNT_RANGE、型違いはE_AMOUNT_TYPE。 |
| R02 | 方法はdeliveryまたはpickup。不明値はE_METHOD。R01を先に検査する。 |
| R03 | pickupは送料0。地域・会員値を参照せず、どの値でも無視する。小計と方法の検査は省略しない。 |
| R04 | deliveryでは地域standard/remoteを先に検査し、不明値はE_AREA。次に会員boolを検査し、不正ならE_MEMBER。 |
| R05 | deliveryの基本送料600。会員trueまたは小計5000以上なら基本送料0。 |
| R06 | deliveryのremoteは基本送料に400追加。基本送料無料でも追加400。成功時は送料と小計+送料、エラー時は送料/合計nullを返す。 |
入力名も最初にそろえます。subtotalは小計、methodは受取方法、areaは地域、memberは会員の値です。deliveryは配送、pickupは店頭受取、standardは通常地域、remoteは追加料金地域を意味します。trueとfalseは真偽値で、引用符付きの文字列とは別です。表のnullは値がないことを表し、送料0円と同じ意味にはしません。
R01とR02で小計と方法を確かめた後、店頭受取なら送料0円を返します。配送の場合だけR04で地域と会員の入力を検査し、R05とR06で計算します。この順序に意味があります。たとえば店頭受取の地域がunknownでも、R03により地域は参照しません。一方、小計がマイナスなら店頭受取でも受け付けません。
また、「会員は送料無料」という短い説明だけでは、追加料金地域の400円まで無料なのか決まりません。本教材ではR06として、基本送料が0円でも400円を加算すると決めました。実務の資料がこの点を決めていないなら、テストを書く人が都合よく補うのではなく、確認事項として返します。未確定のルールから唯一の正解を作ろうとしないことが大切です。
ケース票は、入力と期待結果の根拠が読めればよい
D01を一件のケース票にすると、次のように書けます。実行時の値は、設計した期待値と別の欄に残します。
※表は横にスクロールできます。右側の列まで確認してください。
| 項目 | D01の記載例 |
|---|---|
| 目的と根拠 | 非会員・5,000円未満・通常地域の配送で、基本送料600円が加算されること。R04・R05・R06 |
| 前提 | 架空教材v1.0の計算関数。注文や会員データを保存しない。各実行は独立 |
| 入力 | subtotal=4000、method=delivery、area=standard、member=false |
| 手順 | 4入力をそのまま関数に渡し、返されたstatus・shipping・totalを照合する |
| 期待結果 | status=ok、shipping=600、total=4600 |
| 実行時に追記する情報 | 実行日時、対象版、実際の3項目、判定、不一致があれば報告先の記録 |
表の列を増やす前に、「これを読んだ別の人が同じ条件を作れるか」を見ましょう。「普通の注文」「会員でない人」のような書き方では、普通の意味や会員値の型が曖昧です。この教材なら具体的な4入力を残すだけで再現条件が定まります。ログイン操作や配送先の登録は必要ありません。
D01を自分の言葉で説明する練習では、「4,000円の商品だから600円」だけで終わらせず、非会員、配送、通常地域も添えてください。会員なら同じ4,000円でも基本送料は0円になり、追加料金地域なら非会員の送料は1,000円になります。金額だけを書いたケースが再現に足りない理由を、条件の差で説明できます。
仕様の文章をそのまま写した一覧から一歩進み、どの値を選ぶとルールの違いが表に出るかを考えます。NTTデータの2016年9月8日公開の「テストを開発する」も、仕様の転記に加えてテストの視点と設計技法を使う考え方を説明しています。以下はその一般的な考え方を、独自に用意した送料教材へ当てはめる練習です。
同じ扱いになる入力を分け、代表値を選ぶ

整数の5,000と文字列の「5000」を別のカードにし、金額の範囲と入力型を分けて考える説明図です。
小計の範囲と、入力の型を別の軸にする
小計のすべての整数を順番に試す代わりに、同じルールで処理されると考えられるまとまりを探します。この考え方が同値分割です。まずは方法を配送、地域を通常地域、会員をfalseに固定しましょう。その条件なら、小計の整数は「0円未満」「0〜4,999円」「5,000〜100,000円」「100,000円超」に分けられます。
ここで同じ扱いというのは、合計額がすべて等しくなるという意味ではありません。0〜4,999円では基本送料600円を加える、5,000〜100,000円では基本送料0円にする、という処理のまとまりです。小計4,000円と4,100円の合計は違いますが、送料に使うルールは同じです。何を同じとみなして分けたかを言葉で残しておきます。
負の整数と文字列は、どちらも受け付けない入力ですが、同じ検査ではありません。整数の−1は型が合っていて範囲外です。文字列の「5000」は見た目に数字でも、R01で認めた整数型ではありません。前者の期待状態はE_AMOUNT_RANGE、後者はE_AMOUNT_TYPEです。両方を単に「エラーになる」とまとめると、異なる検査を一つで確認した気になってしまいます。
配送・通常地域・非会員に固定した小計の分類です。型が整数であることを先に確認します。
※表は横にスクロールできます。右側の列まで確認してください。
| 区分 | 代表例 | 期待する扱い | 選ぶ理由 |
|---|---|---|---|
| 整数で0未満 | −1 | E_AMOUNT_RANGE | 有効範囲の下側を拒否する |
| 整数で0〜4,999 | 4,000 | 基本送料600円 | 無料条件に当たらない通常の計算を確認する |
| 整数で5,000〜100,000 | 5,000 | 基本送料0円 | 無料になる側の処理を確認する |
| 整数で100,000超 | 100,001 | E_AMOUNT_RANGE | 有効範囲の上側を拒否する |
| 整数以外 | 文字列「5000」など | E_AMOUNT_TYPE | 数値への自動変換を許していないことを確認する |
代表値4,000円を置くと、境目から離れた値で基本の計算を追えます。600円を加えると4,600円なので、期待値も手計算しやすい値です。しかし4,000円を何度試しても、5,000円ちょうどを無料にし忘れた不具合は分かりません。代表値を選ぶ作業と、境目を追加する作業は役割が違います。
会員をtrueに変えれば、0〜4,999円でも基本送料が0円になり、先ほどの送料による区分はそのまま使えません。地域をremoteにすれば400円の加算が増えます。分類表の見出しに固定条件を付けたのはこのためです。金額だけの表を作った後、ほかの条件を勝手に変えても同じ結論になる、と考えないようにしましょう。
不正入力は、最初に一つずつ変えて調べる
I01〜I07は不正の要因を一つずつ変えます。表にない入力は、I01〜I04では配送・通常地域・非会員、I05〜I07では小計4,000円を含むD01の条件と同じです。全件とも送料と合計の期待値はnullです。
※表は横にスクロールできます。右側の列まで確認してください。
| ID | D01から変える入力 | 期待status | 調べること |
|---|---|---|---|
| I01 | 小計を文字列「5000」 | E_AMOUNT_TYPE | 文字列を勝手に整数へ変換しない |
| I02 | 小計を小数型の5000.0 | E_AMOUNT_TYPE | 見かけが整数でも型が違えば拒否する |
| I03 | 小計を真偽値true | E_AMOUNT_TYPE | 真偽値を金額として受け入れない |
| I04 | 小計をnull | E_AMOUNT_TYPE | 値がない入力を金額として使わない |
| I05 | 方法をexpress | E_METHOD | 未定義の方法を拒否する |
| I06 | 地域をunknown | E_AREA | 配送で未定義の地域を拒否する |
| I07 | 会員を文字列「false」 | E_MEMBER | 会員には真偽値だけを受け入れる |
一件のケースで小計、方法、地域を全部不正にすると、最初の小計検査で結果が返り、その後の方法や地域の検査に進まないことがあります。そのケースが期待どおりに失敗しても、後段の入力チェックが働くとは言えません。I05で方法を調べるときは小計を正しくし、I06で地域を調べるときは小計と方法を正しくします。確かめたい検査まで到達できる条件を選ぶわけです。
I08だけは別の目的で、不正を重ねます。小計−1、方法express、地域unknown、会員は文字列「false」です。小計を最初に検査するというルールがあるため、期待状態はE_AMOUNT_RANGEになります。この一件は優先順を調べるもので、四つの不正検査をそれぞれ独立に確認した件数には数えません。また、小計が正しい場合の「方法より地域が先になっていないか」など、すべての優先関係をこの一件で確かめたわけでもありません。
Python公式の組み込み型の説明にあるとおり、boolはintのサブクラスなので、整数判定の書き方によってtrueを金額として通してしまうことがあります。今回の故意の不具合の一つは、この違いを使いました。これはPythonの教材実装に関する注意であり、どの言語でも同じ判定になるという説明ではありません。入力を記録するときは、trueと数値1を同一視しないでください。
代表を試すことの限界
代表値の通過は、その区分の全入力を実測した証拠ではありません。未入力の引数、配列など別の型、画面上の空欄、文字の前後の空白、通信途中の変換は今回の30ケースに含めていません。追加で扱うなら、対象の入口と仕様を確かめて別のケースを作ります。
同値分割、境界値分析、デシジョンテーブルテストの技法名と位置付けは、ISTQB CTFLシラバスv4.0.1の4.2節を参照しています。日本語用語はJSTQBの2023V4.0.J02も参照できます。両資料は同一の版番号ではありません。本稿の送料ルールと数値例は独自教材であり、公式問題や認定教材ではありません。
境界の前後を試し、5,000円ちょうどの違いを見つける

通常地域・非会員・配送の条件を固定し、小計4,999円/5,000円/5,001円と、送料600円/0円/0円を対応させる説明図です。
小計が有効かどうかと、送料が変わる場所を見つける
金額の境目には二つの役割があります。0円と100,000円は、入力を受け入れる範囲の端です。4,999円と5,000円の間は、有効な小計の中で基本送料の扱いが変わる場所です。送料だけに注目していると上限を超えた金額まで計算してしまう不具合を見落とし、範囲だけを見ていると無料条件の間違いが残ります。
今回の小計は整数なので、隣の値は1円違いです。下限付近では−1、0、1、無料になる付近では4,998、4,999、5,000、5,001、上限付近では99,999、100,000、100,001を用意しました。さらに無効側の隣接値として−2と100,002も置きます。これは本教材で決めた選び方であり、どのシステムでもこの数列だけで足りるという意味ではありません。
たとえば4,999円はR01の範囲内で、R05の5,000円以上には入りません。会員もfalseなので送料600円、合計5,599円です。5,000円なら同じ前提のまま基本送料0円となり、合計は5,000円です。小計が1円上がったとき合計が下がるのは、この教材で段階的な送料無料条件を決めたためです。直感で不自然だと感じても、期待値を5,600円へ書き換えず仕様を確認します。
B01〜B12の全期待値です。共通入力はmethod=delivery、area=standard、member=false。根拠はR01・R05・R06です。
※表は横にスクロールできます。右側の列まで確認してください。
| ID | 小計 | 期待status | 期待送料 | 期待合計 |
|---|---|---|---|---|
| B01 | -1円 | E_AMOUNT_RANGE | null | null |
| B02 | 0円 | ok | 600円 | 600円 |
| B03 | 1円 | ok | 600円 | 601円 |
| B04 | 4,998円 | ok | 600円 | 5,598円 |
| B05 | 4,999円 | ok | 600円 | 5,599円 |
| B06 | 5,000円 | ok | 0円 | 5,000円 |
| B07 | 5,001円 | ok | 0円 | 5,001円 |
| B08 | 99,999円 | ok | 0円 | 99,999円 |
| B09 | 100,000円 | ok | 0円 | 100,000円 |
| B10 | 100,001円 | E_AMOUNT_RANGE | null | null |
| B11 | -2円 | E_AMOUNT_RANGE | null | null |
| B12 | 100,002円 | E_AMOUNT_RANGE | null | null |
小計0円も、この教材では有効です。したがってB02は送料600円、合計600円になります。「0円の注文はありえないだろう」という業務上の推測は、ここで決めた関数の仕様と分けてください。実店舗で0円注文を禁止するなら、その要求を別に定義し、入力を拒否する期待値へ変更する必要があります。
B09の100,000円は上限を含むので有効で、基本送料0円、合計100,000円です。B10の100,001円は無料条件を満たすように見えても、小計の範囲検査で先に拒否されます。先に送料を計算してから範囲外を忘れる実装なら、この対比で不一致が見えます。下限も同様に、負数を0へ丸める挙動を正解として許さない設計です。
4,000円と6,000円だけでは、境目の間違いが隠れる
故意の不具合版strict_thresholdでは、「小計5,000円以上」を「小計5,000円超」として計算しました。非会員・通常地域なら、4,000円の送料600円と6,000円の送料0円はどちらも仕様と一致します。離れた代表値だけで試すと、この不具合版を通してしまいます。
5,000円ちょうどを入れるD03とB06では、期待送料0円に対して実際は600円となり、合計も5,000円に対して5,600円になります。追加料金地域のD04でも、期待送料400円に対して1,000円となります。差額だけでなく、どの条件で差が出たかを見ると、無料になる境目を疑う根拠になります。
D03とB06は入力も期待値も同じです。D03は条件の組合せ表、B06は金額の境目という別の観点を示すため、教材では両方のIDを残しました。実務で必ず同じ操作を二回する必要があるわけではありません。一つの実行ケースに「条件表のこの行」「境界のこの点」という二つの根拠を対応させれば、説明を保ちながら重複実行を減らせます。30という件数は、異なる入力が30通りあるという意味でもありません。
境界の数字は、仕様変更と不具合修正で扱いが変わる
ここで練習です。仕様そのものを「5,000円超で基本送料無料」に変えることが正式に決まったら、どの期待値を変えるでしょうか。非会員で5,000円ちょうどのD03、D04、B06が対象です。D03とB06は送料600円・合計5,600円、D04は送料1,000円・合計6,000円になります。5,001円のB07は基本送料0円のままです。
同じ5,000円でもD07とD08は会員なので、会員条件により基本送料0円を維持します。金額だけを検索して5,000円のケースを全部直すと、今度は正しかった会員の期待値を壊してしまいます。変更する条件のほかに、結果を決める条件がないかを読み直すことが必要です。
一方、元の「5,000円以上」という仕様を守るために誤実装を直す場合、期待値は変えません。失敗したテストを通すために期待値を実際値へ寄せると、間違いを検出する基準を失います。この練習は期待値の検討で、仕様変更版のプログラムを実装・実行した結果ではありません。
境界を選ぶときのチェック
何の区分の端か、端を含むか、最小単位は何か、固定している他の条件は何かを先に書きます。本教材の12件をもって、あらゆる境界値分析の網羅率100%や、全不具合の検出を示すことはできません。
会員・金額・地域の組合せを条件表でそろえる

会員・5,000円以上・追加料金地域の3条件を整理する説明図です。8通りの全入力と期待値は本文の表で確認できます。
まず、表の対象を有効な配送入力に限定する
金額の境目を確認できたら、会員と地域を組み合わせます。いきなり全入力の表を作ると、方法の不正、金額の型違い、店頭受取まで混ざって読みにくくなります。ここでは小計が有効な整数で、方法がdelivery、地域が定義済み、会員が真偽値であることを前提にします。その内側で、送料を決める三つの条件を並べましょう。
条件は「会員か」「小計5,000円以上か」「追加料金地域か」です。それぞれ二つの値なので、この限定した表では2×2×2の8通りになります。金額は5,000円未満の代表に4,000円、5,000円以上の代表に5,000円を使います。表は読みやすさのため一行を一つの条件組合せにしており、行の順番と実行順に特別な依存関係はありません。
基本送料を無料にする条件は、会員または小計5,000円以上です。どちらか片方だけでも成立し、両方が成立したからといってさらに値引きするルールはありません。地域400円は、その基本送料を決めた後に加えます。この二段階を分けると、「送料無料」という言葉で地域料金まで消してしまう取り違えを見つけやすくなります。
D01〜D08の配送条件表です。全件の期待statusはok。方法はdeliveryで共通です。
※表は横にスクロールできます。右側の列まで確認してください。
| ID | 会員 | 小計 | 5,000円以上 | 地域 | 基本送料 | 地域加算 | 期待送料 | 期待合計 |
|---|---|---|---|---|---|---|---|---|
| D01 | false | 4,000円 | いいえ | 通常地域 | 600円 | 0円 | 600円 | 4,600円 |
| D02 | false | 4,000円 | いいえ | 追加料金地域 | 600円 | 400円 | 1,000円 | 5,000円 |
| D03 | false | 5,000円 | はい | 通常地域 | 0円 | 0円 | 0円 | 5,000円 |
| D04 | false | 5,000円 | はい | 追加料金地域 | 0円 | 400円 | 400円 | 5,400円 |
| D05 | true | 4,000円 | いいえ | 通常地域 | 0円 | 0円 | 0円 | 4,000円 |
| D06 | true | 4,000円 | いいえ | 追加料金地域 | 0円 | 400円 | 400円 | 4,400円 |
| D07 | true | 5,000円 | はい | 通常地域 | 0円 | 0円 | 0円 | 5,000円 |
| D08 | true | 5,000円 | はい | 追加料金地域 | 0円 | 400円 | 400円 | 5,400円 |
比べる二件で、一つの条件が結果に効くかを見る
D01とD05を比べると、金額4,000円と通常地域は同じで、会員だけが違います。非会員の送料600円が、会員では0円になります。金額条件がまだ成立していないので、会員条件の効果を単独で観察できる組です。会員条件を無視する故意の不具合版は、D05と追加料金地域のD06で検出されました。
これに対し、D03とD07は会員値が違っても、どちらも小計5,000円以上です。結果はともに送料0円なので、この二件だけでは会員条件を無視する間違いが見えません。条件の値をtrueとfalseの両方で試した、という数え方だけでは不十分です。その条件が結果を変えられる場面を選ぶ必要があります。
D03とD04では地域だけを変え、送料0円と400円の差を見ます。基本送料が無料になった後も地域加算が残ることを確認する組です。D05とD06も同じ差ですが、こちらは会員条件で基本送料が無料になります。金額による無料と会員による無料のどちらでも加算が残るか、別々に追える構成です。
D07とD08は無料条件が二つ同時に成立します。どちらか一方の成立時に合っていたとしても、両方が成立すると処理を重ねてしまう実装なら別の結果になる可能性があります。今回の固定した5種類の不具合にはその誤実装を含めていませんが、ケースの選定理由としては両方が成立する状態を残す価値があります。「検出できそうな間違い」と「実際に作って検出した間違い」は分けて説明してください。
無関係な条件と、起こりえない組合せを混同しない
店頭受取へ切り替えると、R03により地域と会員は送料の計算にも入力検査にも使いません。ここでは「値が何でも結果に影響しない」という意味で無関係です。一方で小計は、店頭受取でも検査します。「配送しないのだから全部の入力が関係ない」と省略しないようにしましょう。
P01では、配送なら不正な地域unknownと、真偽値でない会員文字列「false」をあえて渡します。小計4,000円とpickupは有効なので、期待送料0円、合計4,000円です。この入力は教材関数へ渡せる組合せです。「実店舗の画面では選べそうにない」ことを理由に、不可能な組合せとして削除することはできません。本教材にはその画面がないためです。
実際のシステムで表を減らすときには、そもそも入力できない組合せなのか、入力できるが結果に影響しない条件なのかを区別します。前者を除くには、その入口で起こらないと判断した根拠が必要です。後者をまとめるには、どのルールによって結果に影響しないかを示します。ケース数を小さく見せることだけを目的に、都合の悪い組を落とさないでください。
8通りで確かめた範囲
この8件は、有効な配送入力における3条件の組合せを扱います。小計の全整数、すべての入力型、店頭受取、画面操作、注文の状態変化を網羅した数字ではありません。条件が増えた場合も、「組合せを少し選べば必ず十分」とは言えず、重要なルールと見落としたときの影響から範囲を決めます。
最初に表を作る段階では、結果が同じ行も理由を見える状態で並べてみると理解しやすくなります。その後に、重複をまとめても選定理由を失わないかを考えましょう。今回も送料だけなら0円の行が複数ありますが、会員だけ、金額だけ、両方という成立条件は違います。結果の数だけで必要ケース数を決めないことが、条件表を使う利点です。
実際の結果を残し、不一致を再現できる形で報告する

故意の不具合版で実行したD03の期待送料0円と実際送料600円を比較する説明図です。画面試験の実施結果ではありません。
30件の構成と、残る店頭受取の期待値を確認する
ここまででD01〜D08、B01〜B12、I01〜I07、優先順のI08を確認しました。残るP01とP02を加えると、配送組合せ8件、境界12件、単一の不正7件、複数不正の優先順1件、店頭受取2件の合計30件です。本文の各表と以下の表で、全IDの入力条件と期待結果を追えます。
P01では「無視する」と決めた入力を実際に無視するかを調べます。P02では小計を−1にし、店頭受取の分岐より前に小計検査が残っているかを調べます。送料が0円になるケースだけを置くと、店頭受取なら不正金額でも成功にする誤りを見つけにくくなります。使わない条件と、使い続ける条件を一組で確認する設計です。
I08・P01・P02の全入力と期待結果です。地域unknown、会員の文字列「false」を、配送の場合と店頭受取の場合でどう扱うかも読み比べます。
※表は横にスクロールできます。右側の列まで確認してください。
| ID | 小計 | 方法 | 地域 | 会員 | 期待status | 期待送料 | 期待合計 |
|---|---|---|---|---|---|---|---|
| I08 | -1 | "express" | "unknown" | "false" | E_AMOUNT_RANGE | null | null |
| P01 | 4000 | "pickup" | "unknown" | "false" | ok | 0円 | 4,000円 |
| P02 | -1 | "pickup" | "unknown" | "false" | E_AMOUNT_RANGE | null | null |
期待値は、試験対象の返り値から作らない
本教材の期待値は、6要件から先に数値を決めてケースに記載しています。試験対象の関数を一回動かし、その出力を自動的に「正解」として保存したものではありません。もし関数の誤りを含んだ出力をそのまま正解に使えば、次に同じ誤りが出ても一致してしまいます。
たとえばD02は、非会員・小計4,000円なので基本送料600円、追加料金地域で400円を加え、送料1,000円です。合計は4,000+1,000で5,000円です。この小計と送料の区別が重要です。合計が5,000円になったから基本送料を無料にする、というルールではありません。無料条件が参照するのはsubtotalです。
一方、期待値を手で書けば必ず正しくなるわけでもありません。金額の足し間違い、R05の読み違い、nullと0の混同は起こりえます。ケースの作者と実装の作者が同じ場合には、共通の思い込みも残りえます。自動照合の結果だけでなく、別の確認者が仕様から代表値や境界値を手計算し、期待値の根拠を点検することが大切です。
教材制作者によるローカル実行記録。2026年10月7日01:27:55 UTC(日本時間10:27:55)、Python 3.12.14、架空教材v1.0の計算関数を対象にしました。
※表は横にスクロールできます。右側の列まで確認してください。
| 対象 | 観測した結果 | この結果から言えること |
|---|---|---|
| 基準実装 | 30件中30件が期待値と一致 | 用意した30ケースで3項目が一致した |
| 故意の不具合版5種類 | 5種類すべてで、少なくとも1件の不一致を検出 | 用意した5種類の誤りをこのケース群で区別できた |
| 故意の変更を外した基準実装 | 30件中30件が再度一致 | 元の実装へ戻した状態でケース群が再通過した |
| 実店舗・画面・決済など | 未実施 | 動作や安全性の判断材料にはしていない |
同じ「30件通過」でも、不正入力のケースを成功状態okにしたという意味ではありません。I01のようにエラーを期待したケースでは、E_AMOUNT_TYPEと送料・合計nullが返ることをもって通過としています。テストの合格と、業務処理の成功は別の判定です。
結果の3項目を一組で比べるため、状態が合っていても、エラー時に送料0円を返せばこの教材では不一致です。逆に送料だけを見ていると、エラー状態が違う、合計に送料を足し忘れた、といった問題を見逃します。「どこが合えば合格か」をケース作成時点で決めておく理由がここにあります。
D03の不一致を、入力から再現できるように書く
故意の不具合strict_thresholdを入れた版の、D03の報告見本です。実店舗で発生した障害報告ではありません。
※表は横にスクロールできます。右側の列まで確認してください。
| 項目 | 記載内容 |
|---|---|
| 件名 | 非会員の小計5,000円ちょうどで、基本送料600円が加算される |
| 対象 | 学習用送料関数v1.0/故意の不具合版strict_threshold/Python 3.12.14 |
| 再現入力 | subtotal=5000、method=delivery、area=standard、member=false |
| 再現手順 | この4入力を故意の不具合版に渡し、status・shipping・totalを読む |
| 期待値 | status=ok、shipping=0、total=5000 |
| 実際値 | status=ok、shipping=600、total=5600 |
| 根拠と検出ケース | R05の5,000円以上という条件。D03で検出し、同入力のB06でも検出 |
| 観測範囲 | 計算関数の返り値だけ。画面表示・請求・決済・顧客への影響は未確認 |
件名には「送料がおかしい」よりも、非会員、5,000円ちょうど、600円という違いを入れると、再現の入口が伝わります。ただし原因まで確定していない段階で「比較演算子が原因」と断言する必要はありません。観測した値と、仕様から期待する値を分ければ、調べる人が同じ条件を再現できます。
I03も同じ考え方で追えます。小計を真偽値trueにしたケースの期待はE_AMOUNT_TYPEです。故意の不具合bool_acceptedではtrueが整数のように扱われ、状態ok、送料600、合計601となりました。画面に「true」と打った試験ではありません。JSONで表した真偽値をPythonで受け渡した教材の結果です。入力型を省くと、小計1円の正常計算と混ざってしまいます。
P01では、店頭受取にも地域検査を適用する故意の不具合pickup_area_validationにより、E_AREAが返りました。期待は送料0円・合計4,000円のokです。「unknownを入れたのだからエラーでよい」と判断せず、店頭受取では地域を無視するR03と照らします。不正に見える値を常に拒否することが、すべての仕様で正しいわけではありません。
未実施と不一致を、同じ赤印でまとめない
実行して期待値と違ったケースと、まだ実行していないケースは区別します。また、対象を起動できない、必要なデータがないといった実行不能の状態もあります。状態名はチームの運用に合わせてよいものの、見ていない結果を不合格や合格として扱わないことは共通です。
今回のブラウザー画面は未実施であり、不合格ではありません。決済も試していません。計算関数が30件通ったという事実だけでは、画面で入力を正しく受け渡せるか、注文保存時に金額が変わらないかは分かりません。画面操作の考え方を学ぶ場合は、Figmaプロトタイプの画面遷移と操作テストも参考になりますが、試作品での操作観察と、本物の計算・保存処理の検証は別に設計します。
証拠には、今回のような架空データを使いましょう。顧客の氏名、住所、注文履歴、認証情報を不具合報告へそのまま貼る必要はありません。実データが関係する問題でも、再現に必要な条件を整理し、権限と共有先に合う取り扱いにします。ここで示した報告に画面写真を添えていないのは、画面を実行していないためです。
修正箇所と関連ケースを再確認し、次の仕事へ渡す

故意の不具合5種類を外して基準実装に戻し、30ケースを再実行する流れの説明図です。全システムの安全を保証する図ではありません。
見つけたケースを再実行し、関連する条件も戻っていないかを見る
不具合が見つかったら、修正後に同じ入力で期待結果になるかを確かめます。D03で送料600円だった誤りなら、同じ5,000円・非会員・通常地域・配送で送料0円になるかが最初の確認です。入力を別の金額に変えて通った結果では、元の不一致が消えたことを示せません。
それに加えて、修正がほかの条件へ影響していないかを確認します。無料条件を直す際に会員の扱いや地域加算を変えてしまうと、D03は直ってもD06などが崩れる可能性があります。元の問題の解消を見る確認テストと、変更による別の影響を見る回帰テストは、狙いを分けて考えましょう。この用語の整理はISTQB CTFL v4.0.1の2.2.3節にも示されています。
本教材は小さな関数なので、故意の変更を外した後に全30件を再実行しました。実際の大規模なシステムでも常にすべてを同じ頻度で実行すべき、という意味ではありません。変更した処理、呼び出し元、共有している計算、過去の不具合、実行コストから再確認範囲を決めます。範囲を減らしたなら、何を省いたかも残します。
固定教材で実際に作った5種類の故意の不具合と、それぞれを検出したIDです。検出IDの数は、別々の不具合数を表すものではありません。
※表は横にスクロールできます。右側の列まで確認してください。
| 故意の不具合版 | 入れた間違い | 不一致を検出したID |
|---|---|---|
| strict_threshold | 5,000円以上を、5,000円超として扱う | D03・D04・B06 |
| remote_free_dropped | 基本送料が無料なら、地域加算400円も消す | D04・D06・D08 |
| ignore_member | 会員による基本送料無料を無視する | D05・D06 |
| bool_accepted | 小計の真偽値trueを整数として受け付ける | I03 |
| pickup_area_validation | 店頭受取でも不要な地域検査を行う | P01 |
この5種類は、学習のために制作者が意図的に入れた誤りです。実案件で五つの障害を解決した実績ではありません。また、今回の「修正後」は個別に別の修正プログラムを開発したという意味ではなく、故意の変更を外して元の基準実装に戻した状態を指します。その状態で30件が再通過したことを実行記録に残しました。
5種類すべてを検出できても、未知の不具合が残っていないとは言えません。テストデータに含まれていない型や、今回は実装していない画面・通信・保存の問題はこの実行では調べられません。成果を説明するときは、「用意した5種類を検出した」と、対象と数え方をそのまま書くと伝わります。
演習:地域加算を400円から500円へ変えたら
最後に、R06の追加料金だけが400円から500円へ変わる仕様変更を考えます。ほかの条件はそのままです。まず期待値を変えるべきケースを、本文のD表から選んでください。小計や会員の列より、地域がremoteの行をたどると見つけやすくなります。
答えはD02、D04、D06、D08です。D02は基本送料600円に500円を加え、送料1,100円、合計5,100円になります。D04とD08は送料500円、合計5,500円、D06は送料500円、合計4,500円です。小計の値自体や、会員条件の判定を変更する必要はありません。
期待値を変更しないケースにも確認の意味があります。通常地域のD01・D03・D05・D07は地域加算がなく、値は変わりません。境界B群も通常地域なので同じ期待値です。店頭受取P01は地域を使わないため送料0円を保ち、P02は小計エラーを保ちます。不正入力I群でも、加算処理に入る前にエラーとなる設計を維持します。変更対象の行だけを見ると、すべての地域へ誤って500円を加える変更を見逃しかねません。
さらに、追加料金地域で上限100,000円の計算も追加で見たい、といった判断はありえます。その場合は既存30件を密かに置き換えず、目的と期待値を付けた追加ケースとして管理します。この演習は変更時の選定を考えるためのものです。固定教材と実測結果は400円の原仕様のままで、500円変更版を実行済みとはしていません。
小さな成果物に、選んだ理由と未確認範囲を添える
練習の成果を見本にするなら、30行の一覧だけを見せるより、なぜその入力を選んだかを短く添えましょう。「4,000円は無料条件から離れた代表」「5,000円は条件が切り替わる端」「会員trueは金額条件が成立しない4,000円と組み合わせた」と説明できると、表を埋めただけではない判断が伝わります。
渡すものは、6要件の仮仕様、条件の分け方、全ケースの入力と期待結果、実行結果、未確認範囲を基本にできます。対象版と実行日時が分かれば、後から仕様を変えた際にも、どの結果を読み直すべきかを追えます。以前の失敗記録を合格に塗り替えるのでなく、新しい実行結果を追加し、修正前後の差を残してください。
- D01を、4入力と3つの期待項目を省かず説明できる。
- I01の文字列とB06の整数を区別し、異なる期待値の理由を言える。
- B05・B06の金額の差と、送料の切替を手計算できる。
- D01とD05を比べ、会員条件が結果に効く場面を示せる。
- P01とP02を比べ、無視する条件と残す検査を説明できる。
- 不一致の報告に、対象版・入力・期待値・実際値を分けて書ける。
- 30件通過から言えないことを、未確認範囲として示せる。
この教材だけで、実際の受託で必要な知識や責任範囲をすべて満たすわけではありません。副業の案件を検討するときは、テスト設計だけの支援か、実装・環境構築・運用まで求められるのかを別に確認します。仕事の選び方は、プログラミング副業案件で確認する仕様・責任・準備を参考に、対応できる範囲を具体化してください。架空教材は学習例として示し、顧客の実績と混同させないことも大切です。
テストケースの作り方で迷ったら、「この入力を選んだのは、どの違いを見たいからか」へ戻ってみましょう。同じ扱いの代表、扱いが変わる境目、複数条件の組合せという三つの見方を使うと、次に足すべきケースと、ただ重複しているケースを考えやすくなります。まずはD01、B06、D05、P01を自分で説明し、その後に全30件を読み比べるところから始めてください。
参考にした技法資料:ISTQBおよび同シラバス著者によるCTFLシラバスv4.0.1(2024年9月15日)、JSTQBのFoundation Levelシラバス2023V4.0.J02、NTTデータ「テストを開発する」(2016年9月8日)。資料の著作権は各権利者に帰属します。本稿は独自教材による解説で、公式の資格認定・推奨・承認を示すものではありません。