実装詳細テスト要るのか問題(反語)

備忘録です。

テストとは書きたいけど書きたくないという大変アンビバレントな状態に人間を置く深淵の魔物。

テストの分け方についても色々な指標があるけどここでは便宜上「実装詳細テスト」「サービステスト」「E2Eテスト」の3つにわけて説明をします。

テストとは

実装詳細テスト: 書いた実装に依存するテスト。ある関数にこういう入力をしたらこういう出力が返ってきますよ~みたいなやつ。アプリケーションの他の部分に依存せずその関数とテストを別の場所にもっていっても動くが、実装を変更するとテストも変更が必要になる。

E2Eテスト: エンドユーザーが行う操作と同じ操作を行い期待した入力に対して期待した出力が返るかを調べるテスト。本番または本番と同じに作られたデプロイされた環境を使うもの。

サービステスト: それ以外(雑)。もっと言うと、「書いた実装になるべく依存せず、実装を変えても動き続ける」「他のサービスやシステムに依存しない、基本的にインターネットへのアクセスも行わない(ローカルサーバーは可)」の2つを備えたテスト。

実際にはエンドユーザーと同じ操作を行うテストなんだけど裏側がスタブになってて本番環境にアクセスしないみたいな中途半端なやつもあると思うけど一応こういう分け方にしてみる。

実装詳細テスト要るのか

E2Eテストがつらく厳しく基本的に誰も書きたくないというところはまぁ人類の合意なのではと思っている。当然書かないわけにはいかなくてしょうがなく書いてる人はいっぱいいると思うけど。

問題は実装詳細テストの方でこれが要るのかという話。これはアプリケーションの性質とかにもよるので一概には言えないけど通常のアプリケーションやサービスなら不要なのではと思う。そもそも「常にsemanticsを考えよ」という設計の金科玉条(これは私が勝手に言ってることだけど)からすると、アプリケーションの中で定義された関数のふるまいはアプリケーションのsemanticsなどでは決してないのでそんなものをテストする必要はないでしょという感じ。あるいは実装詳細テストを書きすぎると機能追加や修正でテストの変更が必要になって逆にテストが開発を妨げてしまったりして逆効果になることさえある。そもそも我々はサービス開発等で忙しくちまちまテストを書いている余裕などないので実装詳細をチェックする必要などないのだ(逃げ)。

サービステストはもちろん書く。というかこれがすべて。そこまで難しくない世のほとんどのプログラムならサービステストをsemanticsに乗っ取って書くだけでカバレッジ100%にできると思う。

実装詳細テスト要らないのか

じゃあ実装詳細テスト書いちゃだめかというとそうではないです。普通に必要になることもある。

  • ライブラリとして切り出す場合: ライブラリはそこでexportされる関数がsemanticsになるので今度そのテストはむしろ書いてくださいとなる。同じプログラムでも使われ方によって意味が変わってくるのでしょうがない。
  • スタブとかの都合: サービステストは通常複数のモジュールをまたがるのでローカルサーバーとかでテストできるのが一番良いのだけど使ってるSDKの都合とかでそういうテストが書きにくいのでこの画面のテストだけは実装詳細でやりますみたいなのはアリだと思う(というかしょうがない)
  • 実装が非自明な場合: 何かの方程式を超多ステップで解くとか複雑なアルゴリズムを手書きするとか まぁ実装が非自明な場合はやった方がいいですね 当たり前や

ウェッブサービスの構成

今こういう感じでやっておる

  • サーバーサイド
    • SDK: サーバーサイドが提供するAPIをたたくだけのSDKを用意する; クライアントサイドで読み込んで使う
    • サーバーサイドのコード
    • サービステスト: SDKに対するテストをがりがり書く
    • (必要があればモジュールごとに)実装詳細テスト
  • クライアントサイド
    • (必要があればコンポーネント/画面ごとに)Viewの詳細テスト

ひとまず困ってない。あとテストはやっぱり書きたくない。

semantics、意識していこうな