テストの緑色は、何を証明しているのか
うまく動いた一回より、「してはいけないことを止めた一回」を読む。試験の準備・刺激・観測から、安全性の根拠と限界を見分けます。
本文の説明・図・掲載コードだけで読み進められます。出典リンクは、権限のある人向け(非公開GitHub)です。GitHubで閲覧権限がある方だけ開けます。
この記事でわかること
- テスト名より、入力と最後の検査を読む
- 残高・記帳件数・所有者・競合・認証を別の不変条件で確かめる
- 試験コードの存在、過去の結果、現在の稼働確認を区別する
この記事の目次
「書いてある」「通った」「いま動く」は三段階
テストは、決めた条件のもとで期待どおりの結果になるかを調べる実験です。ソースにテストがあることは、どの約束を守ろうとしているかの証拠になります。でも実際に実行して合格したことや、今の稼働環境も同じ状態であることまで証明しません。
読み分けたいのは、検査の定義、特定の時点・環境での実行結果、現在の環境の観測です。このサイトでは固定コミットのコードを読んでおり、銀行の試験やデータベース操作を実行していません。したがって以降の「確認する」は、テストに書かれた検査内容を指します。実行済みという報告ではありません。
この区別は慎重な言い回しだけの問題ではありません。銀行用テストは顧客や口座の例を作り、意図的に故障を入れます。connection.mjs はループバックのホストと専用の minibank_*test というデータベース名を要求し、外部のDBへそのまま接続しないための歯止めを置いています。テストコードを本番の修復手順として真似てはいけません。
「一度だけ」を返事の数ではなく記帳件数で見る
架空のテストで、葵さんが100円を持ち、蓮さんへ10円を送るとします。同じ依頼の確定を三回並列に呼び、三回とも「完了」が返ること自体は異常ではありません。三つの別件を成立させたのでなく、一つの結果を三つの呼出しへ返せばよいからです。
banking.test.mjs の対応する試験は、戻る振込IDが一種類であることに加え、振込行の増分が1、仕訳見出しが1、仕訳内訳が2であることを調べます。残高も葵さん90円、蓮さん10円を検査します。HTTPの成功だけ、あるいは同じIDだけを見るより、隠れた二重記帳を見つける観測になっています。
失ってしまった応答の再取得を想定し、その後もう一度受付や確定を呼んでも同じ結果になることを確認します。別の試験では、同じキーのまま依頼人名やメモを変更して TR009 になることを調べます。「再送なら許す」と「内容のすり替えは許さない」を一組で読むと、キーの役割が具体的になります。
実装の読み方:期待する数を先に書く
これは検査の狙いをまとめた読み取り用の擬似コードです。銀行処理を実行するコードではありません。
同じ10円の依頼を3回確定
返る振込IDの種類 = 1
振込行の増分 = 1
仕訳見出しの増分 = 1
仕訳内訳の増分 = 2
葵さん 90円 / 蓮さん 10円拒否されたことと、お金が動かなかったことを組にする
安全性の試験では、正しい入力を通すだけでなく、不正な操作を止めた後の状態が大切です。たとえば他人の依頼を確定する、顧客が管理側の入金を呼ぶ、自分で cached_balance や本人確認状態を書き換える、匿名で内部の仕訳へ触る、といった境界を直接試しています。画面でボタンが隠れているだけでは防げない操作です。
振込依頼の受付後に口座を凍結する試験は、確定時に失敗すること、仕訳や振込の件数が増えないこと、残高が変わらないことを一緒に確かめます。受付時点の許可が永久に使えるわけではなく、実行前の状態変化が効くことを見ています。
監査の書込みを意図的に失敗させる例もあります。金融の行数と両残高が元のままで、依頼には内部の機微な例外文ではなく失敗コードが残ることを検査します。一方、行がゼロの仕訳見出しはコミット時に拒否され、元帳の既存行の更新も拒否されます。エラーの有無だけで終わらず、その後にどの状態が残ったかを見るのが、不変条件の読み方です。
同時に呼んだだけで、本当に競合したと言えるか
別々の80円の支払いが、100円の同じ残高を使おうとする試験では、一方が完了し、もう一方が残高不足となり、残高20円を保つことを検査します。また逆方向の振込、日次上限を同時に取り合う振込も試験の対象です。「別キーなら二件とも通す」ではなく、各件の条件を最新の状態で判断するためです。
ただし、プログラムから二つを同時に呼んでも、偶然きれいに順番に実行されてしまえば、ロック待ちの問題を踏めないかもしれません。products-concurrency.test.mjs は、この限界を意識した構造です。別のDB接続を使い、片方の処理を未確定に保ち、もう片方が実際にその接続を待っていることを pg_blocking_pids で観測してから先行処理を解放します。
ここで振込と定期預金の作成・解約・満期、口座解約と商品の処理、入出金と定期預金解約など、異なる業務が同じ口座を触る組み合わせを試します。最後には商品の状態に加え、キャッシュと元帳の一致、全仕訳の貸借を確かめます。単体機能の試験が通っていても、共有資源の競合は別に調べる必要があります。
認証を済ませた試験用データは、実物の認証ではない
金融の業務規則だけを細かく試すには、毎回人が認証アプリを操作すると遅く不安定になります。そこで banking.test.mjs は、検証済みの認証記録を模した試験用データを使います。mfa-receipt-fixture.mjs 自身も、これは実際のAuthやTOTPの証明ではないと明記しています。
認証のSQL受入試験も、本人、セッション、要素、チャレンジ、認証履歴の行を試験環境で準備します。その上で、古い記録、別人、別セッション、失効したセッション、変わった金額や受取先、削除・無効化された認証要素を拒否するかを調べます。新しい検証を別セッションへ付けても、古い認証済みセッションへ流用できないかという否定例もあります。
これらは、データベースの判断条件を検証する強い手掛かりです。ただしブラウザから実際の認証サービスへ進み、認証アプリのコードを入力して戻る一連の経路まで、この試験だけで証明したことにはなりません。業務規則、認証境界、HTTP、画面、配備された設定を、どの試験が扱うか分けることで、未確認の部分を隠さずに済みます。
新しい機能では、守る範囲も変わる
価格機能の試験では、新しい金利の版が有効になっても以前の契約の金利が変わらないこと、古い見積りや他人の見積りでは契約できないこと、同じ見積りを使い直せないことを調べます。これは単なる数式の正しさより、「いつ誰にどの条件を約束したか」という不変条件です。
デジタルツインの試験は別の意味で広い範囲を見ます。同じ入力とシード値で結果を再現できることや、試算の前後で本来の元帳・商品・契約・上限が変わらないことを検査します。模型の結果が計算上つじつまの合うことと、将来を正しく予測することは別です。架空の仮定の模型について、テスト合格から予測精度まで主張することはできません。
実行結果を読むときは、対象のコミット、試験環境、実行した種類、合格・失敗・未実行、使ったfixtureを合わせて確認します。何百件という件数だけでは、その変更に必要な否定例が含まれるか分かりません。このサイトで確かめたのは検査の設計です。現在の稼働保証や今回の試験合格という見出しへ置き換えず、次に何の証拠が必要かを考える読み方を勧めます。
根拠:価格の版と契約スナップショットの試験 ↗(非公開GitHub・要権限)
出典と、確認できた範囲
以下のリンクは非公開GitHubへの出典で、閲覧権限が必要です。本文はリンク先を開かなくても読める構成です。固定コード・設計資料を参照していますが、今回、この読み物のために銀行の取引やDB操作、本番試験は実行していません。実装や資料にある検査と、こちらで実施した検証を混同しないようにしています。
- 金融の基本不変条件 ↗(非公開GitHub・要権限)
重複、残高、権限、監査、失敗後の行数を調べる試験 - 実際の競合を作る試験 ↗(非公開GitHub・要権限)
別接続のロック待ちを観測した上で状態を確認 - 銀行試験の接続先制限 ↗(非公開GitHub・要権限)
破壊的fixtureを使うため専用ローカルDBに限定 - 試験用認証記録 ↗(非公開GitHub・要権限)
業務規則試験が実物のAuth/TOTP証明ではない境界 - 依頼に結び付いた認証の否定例 ↗(非公開GitHub・要権限)
古い認証、所有者・セッション違い、内容変更を拒否 - 価格変更の試験 ↗(非公開GitHub・要権限)
既存契約、見積り期限、所有権、再使用を検査 - 模型の試験 ↗(非公開GitHub・要権限)
再現性と実績への不書込みの定義
MiniBankは学習・検証用の銀行アプリです。架空の金額や人物は、仕組みを説明するための例です。
つながる読み物
ここまで読んだ記録を、ひとつ。
自分のペースで。あとから取り消すこともできます。