テストコードが増えてきて、1本1本のテストがどんな仕訳を登録しているのか、コードを目で追うだけではしんどくなってきたので、仕訳登録のテストコードを、簿記の記法で読めるようにするツールを作った。
会計アプリのテストは「読める」けど「理解しづらい」
仕訳を登録するテストコードは、こんな形をしている。
(new TransactionRegistrar)->register($closedYear, [
'date' => '2025-06-10',
'description' => '消耗品購入',
], [
[
'sub_account_id' => $expense->id,
'type' => JournalEntry::TYPE_DEBIT,
'net_amount' => 10_000,
],
[
'sub_account_id' => $cash->id,
'type' => JournalEntry::TYPE_CREDIT,
'net_amount' => 10_000,
],
]);
コードとしては正しい。でも「どういう仕訳を登録しているか?」を理解しようとすると、見たいのは「日付・摘要・借方・貸方」の1行分の情報だけなのに、1つの仕訳が20行に展開されていて、とても読みにくい。
ボツになった案たち
最初に考えたのは、テスト用のヘルパー。
$this->仕訳($year, '2025-06-10', '消耗品購入', 借方: ['消耗品費', 10_000], 貸方: ['現金', 10_000]);
見た目は仕訳帳そのもの。でもこれには問題があって、テストが実際のAPIと違う形のコードを通ることになる。変換層にバグがあれば、レビュアーが見ている仕訳と実際に登録される仕訳がズレる。ヒューマンチェックの信頼性を上げたいのに、チェック対象が増えては本末転倒。却下。
次に考えたのが、テスト実行後のDBを仕訳帳形式でダンプする案。これも却下。バリデーションエラーなどで登録そのものが失敗するテストでは、DBには何も残らない。見たいのは「テストが何を登録しようとしていたか」なので、登録が失敗した時にこそ確認できないと意味がない。
最終形:テストソースを「表示だけ」変換するツール
行き着いたのは、テストコードには一切手を入れず、レビューのときだけソースを読みやすく表示する独立ツール。PHPのASTを解析して、仕訳登録の文だけを簿記の記法に置き換えたフルソースを出力する。
冒頭の消耗品購入の例なら、こう表示される。
▶ 2025-06-10 | 消耗品費 10,000 / 現金 10,000 | 消耗品購入
▶が仕訳登録。日付 | 借方 金額 / 貸方 金額 | 摘要の並びで、/の左が借方、右が貸方という簿記の教科書記法。日付は固定幅なので借方の開始位置が常に揃い、長さがまちまちな摘要は右端に寄せてある。$cash->idのような変数は同メソッド内のgetSubAccountByName('現金', '現金')を遡って科目名に解決し、解決できない式は推測せず原文のまま出す。
仕訳明細をアサートしている箇所も、同じ発想で変換する。元のコードはこう。
$this->assertSame([
[
'account_name' => '現金',
'sub_account_name' => '現金',
'amount' => 140_000,
'type' => 'debit',
],
[
'account_name' => '借入金',
'sub_account_name' => '借入金',
'amount' => 20_000,
'type' => 'credit',
],
], $rolloverData['opening_entries']);
これが1行になる。
✓ 現金 140,000 / 借入金 20,000 | $rolloverData['opening_entries']
✓が仕訳明細のアサーションで、こちらも借方/貸方の記法は登録の▶と揃えてあり、比較対象の式が右端に来る。それ以外の行(変数代入やメソッド呼び出しなど)は原文のままなので、テストの流れと仕訳を同じ画面で追える。
まだ物足りないところや、うまく変換できないところもあると思うが、とりあえず、今(これから)開発する部分に関しては、借方・貸方を脳内変換していた頃に比べればだいぶ見やすくなった。
ただし、これはあくまでレビューを助けるための表示であって、変換結果そのものが正しさの根拠になるわけではない。読んでいて何か違和感があった時は、変換結果を疑って元のテストコードに戻って確認する、という前提を崩さないようにしたい。変換ツール自体にバグが紛れ込む可能性は普通にある。
学び
- テストの読みやすさとヒューマンチェックのしやすさは別物。後者のためにテストコード自体を変えるのは筋が悪い
- 「実行に使う変換」と「表示に使う変換」ではバグの影響がまったく違う。表示専用ならテストの信頼性を損なわない
- 一度捨てた案でも、前提(用途)が変われば最適解になる
パーサはPHPUnitが推移的に依存しているnikic/php-parserをそのまま使ったので、依存の追加もゼロで済んだ。
余談だが、変換結果を見ていて、typeをJournalEntry::TYPE_DEBITのような定数で指定しているテストと、'debit'という文字列で直接指定しているテストが混在していることに今更気づいた。今回のツールとは別の話だが、自戒として書き残しておく。