多すぎるユニットテストは却ってよくない?
私が実践しているテストコードのリファクタリング
OffersDeepDive2025/1/30
フューチャーアーキテクト
渋川よしき
OffersDeepDive2025/1/30 1
お前誰よ:渋川よしき
会社:HondaR&D→DeNA
→フューチャーアーキテクト(2017/9-)
家族:妻、娘x3
好きな言語
TypeScript®/Go/Python
趣味
*インラインスケート(歴20年以上)
SNS
*github.com/shibukawa
*x.com/shibu_jp
OffersDeepDive2025/1/30 2
テスト駆動開発やっていますか?
OffersDeepDive2025/1/30 3
伝統のテスト駆動開発
1.ユニットテストを書き
2.テストを通す最低限のコードを書き
3.リファクタリング
これを高速に回す。
厳格に最低限のコードのみを書く原理主義的な人は少ないかもしれませんが、今日聞いてい
る方々はある程度のテストは書いているとします。
OffersDeepDive2025/1/30 4
テスト駆動開発のメリット
高品質なコードが書ける
バグが少ない
インターフェイスがクリーンになる
開発効率が上がる
テストコードがドキュメントになる
リファクタリングがしやすい
OffersDeepDive2025/1/30 5
(おまけ)現代のテストコードとリズム
Goだと、関数のI/Fを定義するとコード生成でテーブル駆動テストの雛形を出してくれる
入出力の構造体とかの定義とか頑張り始めると、行数が少ないコードだと、テスト
コードの中身を書き始めるまでの準備の時間が50%とかになってしまう
必要があるまでreturnerrを書かないというのも無理がある
あんまり気にしない
あるいはある程度形が決まるまでテーブル駆動テストをしないというのも手
OffersDeepDive2025/1/30 6
プログラミング言語とか作ったことありますか?
OffersDeepDive2025/1/30 7
プログラミング言語を作る(インタプリタ)
トークン分割
構文解析→抽象構文木
評価器
OffersDeepDive2025/1/30 8
プログラミング言語を作る(コンパイラ)
トークン分割
構文解析→抽象構文木
ジェネレータ
OffersDeepDive2025/1/30 9
プログラミング言語を作る(改良)
トークン分割
構文解析→抽象構文木
最適化
SSA形式に置き換え
シンタックスシュガーを展開
定数の演算はやっちゃう
評価器orジェネレータ
OffersDeepDive2025/1/30 10
私はプログラミング言語作りたいとは思ってないよ
という人が今日聞かれている方の大半であると思うが、テキストや何かしらの情報を元に、
意図を取り出してきてタスクを行う、他のものに変換するという構造はいろいろなソフトウ
ェアに偏在する
例えば
Excel→RDBのDDL
YAML→APIコードの雛形
なので、自分とは関係ないよ、と言わずにZoom抜けたりしないでね!
OffersDeepDive2025/1/30 11
APhilosophyofSoftware
Design
いろいろ良いことが書いてある本
洋書しかないが、ネットでぐぐると日本語の
読書感想文もいっぱい出てくる
OffersDeepDive2025/1/30 12
浅いモジュール
深いモジュール
よく出てくる図
浅いモジュールはAPIの数の割に内
部のロジックがシンプルで他への
依存もあまりない
深いモジュールは内部のロジック
が複雑な割にAPIはシンプル
OffersDeepDive2025/1/30 13
テスト駆動開発と浅いモジュールは相性が良い
世の中の良いコードというのはこちらを指向していることが多い
ボトム(ドメインロジック)で品質を上げてそれを組み立てて全体の品質を上げる
ウェブアプリケーション(JSON色付け係・SQL組み立て係)は浅くなる
レイヤーをたくさんわけても、パッケージパブリックな要素が増えるのは浅い
リファクタリングもシンプル
コードと責務の移動、共通コードの括りだし、分割程度
公開APIに対してテストをしよう→それでも十分にカバレッジは上がる
OffersDeepDive2025/1/30 14
深いモジュールは公開APIが少ない
深いモジュールの例
正規表現の重要な入力は1つの文字列でそれのコンパイルを行う
HTTP/2はHTTP/1とAPIが同じだが内部のロジックは大幅に異なる
リズムよくテスト駆動開発を行うには
ユニットテストコードはパブリックなAPIに対して書こう、とよく言われるが
公開APIにのみテストをしようとするとゴールが遠すぎる
プライベートな要素に対してもテストを書くか?
OffersDeepDive2025/1/30 15
プライベートテストの作戦
OffersDeepDive2025/1/30 16
作戦の比較
1.愚直にパブリックなAPIのみ
内部が全部そろうまでなかなかゴールが見えない
2.サブパッケージの公開要素にしてテストする
汎用で独立してパッケージ公開しても価値があるコードならあり
変更影響がパッケージに分散してやりにくくなるだけで生産性はマイナス
教条的に「パブリックなテストのみ」にコードを無理やり合わせた形
3.プライベート要素もテストを書く
Goの場合は同一パッケージ内であればプライベート要素のテストはできる
OffersDeepDive2025/1/30 17
重要な前提
経験上、処理系は何度実装してもなかなか一発で設計できるようにならないし、内部構
造の変更の頻度はパッケージ分けても変わらない
プライベートな要素は実装者も1-2週間あればすっかり忘れる
テストでエラーが出ても、仕様がそもそも明文化されてないので何が悪いのかどう治す
べきかテストを直すべきかすぐにわからないことが多い
OffersDeepDive2025/1/30 18
フェーズによって作戦を変える
1.最初はプライベートののテストをガンガン書く
テスト駆動開発のリズムで開発
ゴールが遠すぎて心が折れるのを回避
2.一通り上流までの機能がそろったら公開APIのテストに
置き換えていく
処理系の入力テキストと出力に対するデータ駆動テ
ストにしていく
3.プライベート向けのテストは捨てる
OffersDeepDive2025/1/30 19
多すぎる/無駄なテストは開発速度を落とす
テスト駆動のテストコードは実装された瞬間が最大価値
既存のテストが新しいバグを見つけることは基本的にない
リファクタリング、依存ライブラリの仕様変更の発見で力を発揮
メインのコードと構造が接近しすぎたテストは品質に寄与しない
コードを直すたびに修正が必要なテストは手間が増えるだけで保証にならない
内部APIのテストはこうなりがち
なので思い切って捨てる
OffersDeepDive2025/1/30 20
この時に書いた技術ブログ
testdataの中のフォルダをループで回して入力ソースを
読み込んで期待する結果と比べるテスト
中間出力をワークフォルダに書き出してデバッグしたい
というのを書いたら今日のお話が来ました
https://future-architect.github.io/articles/20241016a/
OffersDeepDive2025/1/30 21
常に上流のテストで代替すべきか?
ウェブフロントエンドのE2Eテストはかなり速度が遅い
並列動作もさせにくい
バリデーションは細かい規則の網羅はユニットテス
トで行い、E2Eテストは「バリデーションが実行さ
れた」のチェックだけにするなど分担をきちんとす
ることでテストが遅くなるのを防ぐ
ただし、並列テストしやすくなるとか技術的なイノ
ベーションがあれば変わる可能性はある
https://kentcdodds.com/blog/the-testing-trophy-and-
testing-classificationsから引用
OffersDeepDive2025/1/30 22
常に上流のテストで代替すべきか?
ウェブフロントエンドでの単体テスト・統合テスト議論は動機は少し違う
画面に表示するコンポーネントありきのロジックは単体テストしても全体の品質へ
の寄与は小さい
トップダウンで作ってロジックが太ったので切り離す、というのが一般的だと思う
言語の場合の内部構造はボトムアップで実装していくが上流の要件変更で変わりやすい
下側で品質を担保担保がやりにくいという特性
画面のUIコンポーネントとはやや似ている
画面のテストもユニット→インテグレーションの流れ(testing-libraryとか)
OffersDeepDive2025/1/30 23
落ち穂拾い
テストの名前
最終的なAPIのテストは公開要素に対するユニットテストと言えるが、プライベート
要素からするとインテグレーションテスト
この辺りの名前は相対的なものなので、この発表を持って「インテグレーションテ
ストの寄るのが正しい」みたいなことは言えない
外から見えない挙動について
キャッシュやリトライ、最適化がうまく走ったかなどは外部からは見えない挙動
これが要件としてある場合はそこのプライベートなテストは必要かもしれない
あるいは統計情報やログとして取り出せるようにしてそこでテストするのも手かも
しれない
OffersDeepDive2025/1/30 24
まとめ
公開機能以外は実装者も1-2週間あれば忘れる
プライベートはテストしないというが最初からプライベートのテストを書いてはいけな
いわけではない
最初は補助輪のつもりでプライベートのテストを書くことはあるが、のちに意識してき
ちんと捨てていく
OffersDeepDive2025/1/30 25
みてね
OffersDeepDive2025/1/30 26

多すぎるユニットテストは却ってよくない?私が実践しているテストコードのリファクタリング