効果の高いテストについて考える

テストエンジニアという奇異な立場にいる。 普通にプロダクトメンバーの一員だが、プロダクト自体のコードはあまり書かず、品質という観点から良かれと思ったことをする。大体グーグルのテスト本に載っているSETをロールモデルとしている。

テストから見えてくる グーグルのソフトウェア開発

テストから見えてくる グーグルのソフトウェア開発

SWTは、例えばエンジニアがテストを書きやすいようにライブラリを作ったり、テストがリリースのネックにならないように高速化したり、手動テストを支援するようなサポートツールを作ったりするのが役割となる。普通に単体テストも書く。(が、それはあまり理想ではなくて、本当はそのコードを書いた人が単体テストも書くべきだ。)

しかし、現実世界であまりそういう人を見なくて、先人の知恵を借りられずやきもきしている。もしかしたら同じことを感じている人がいるかもしれないと思ったので、何かのたしになればと思い、最近考えたことをメモしておく。

効果の高いテストと低いテストがある

テストには効果の高い / 低いがあり、効果の低いテストを書いてしまうと、テスト自体のメンテナンスコストの方が大きくなり、開発を阻害する要因となる。まずはこの点について認識を持つべきだと思う。

効果の低いテスト

例えば、セッターとゲッターしかないクラスにテストを書いたとする。ここにはロジックが含まれていないので、テストする価値はほとんどない。だが実際にCIしていると、意外と落ちたりする。落ちる原因はプロパティ名が変わったとかそんな理由である。そしてプロダクトコードではなくテストの方を修正する。テストコードを修正しなければならないのは、言い換えれば良いテストができていなかったと言えるのではないかと思っている。

少し話は逸れるが、TDD がいまいち浸透せず、アイツは死んだとか言われるのは、こういうトレードオフに対して無自覚だからだと思う。TDD はいつもテストを書くことを強制する。つまり、効果の低いテストも書かなければならない。こういった非効率は現場では許容できず、自然淘汰される。TDD は死んだと言われて久しいが、では次にどうあるべきかというのがなかなか出てこない。それは、「テストには効果が高い / 低いが存在する」というスタート地点が共通認識として持てていないからのように思う。

効果の高いテスト

数値計算正規表現などを扱う単体テストは効果が高い。例えばゲームだと、レベルアップ・ダメージ計算・エネミーエンカウント・アイテムドロップ等のロジックなどがこれにあたる。こういう部分は手動でテストしづらいので機械からテストしたほうがよっぽど効果が高い。もう少し抽象的な言い方をすると、効果が高いのは、入力に対する出力がわかりづらいロジックのテストだ。そりゃそうだろという話になるが、ではどこからが「数値計算的な部分のテスト」でどこからが「セッターとゲッター的な部分のテスト」なのか、線引きが難しい。この線引きを上手く行えるかどうかが勝負という感じがする。

また、API結合テストのようなものも効果が高い。単純に、少ないテストコードで多くの部分をカバーできる。ただし、細かな状態まで結合テストでカバーしようとするのは悪手で、色々やり過ぎるとある時点で管理コストがテストによるメリットを凌駕し、効果の低いテストに転換する。

カバレッジ意味なし

どれだけ効果が高いテストができているかは、カバレッジでは測れない。カバレッジが高いからといって十分な品質が保たれていることにはならないし、世間で思われているよりもそれらの相関はずっと低い。というか、カバレッジ至上主義に陥るとセッターとゲッターのテストを書き始めるのでたちが悪かったりする。もうすっかりカバレッジ90%ですとか言われても感動しない体になった。

モバイル端末操作の自動化しんどい

一昔前から selenium でPCブラウザ操作の自動化を行う流れはあったが、これをさらに発展させ、モバイル端末でも行えるようしようという試みがある。代表的なツールとしては、appium, calabash などが挙げられる。これらのツールは、最近はまずまず安定して動くようになった。しかし、ツールがどうこうというより、モバイルをとりまく環境が複雑すぎて、総合的な安定性に欠ける。その部分について少し書きたい。

第一に、appium や calabash といったツールサードパーティ製だというのが致命的だ。こうすると、どうしても最新のOSに追従するのが後手になる。最新OSのリリースが終わった後に対応完了というのはザラであるどころか、リリース後一週間以内に対応できれば御の字で、確か iOS7 の時は cocoa 側にバグがありしばらく対応できなかった思い出がある。大体最新OSリリース前にテストを済ませたいはずなので、これでは要件を満たせないのではないだろうか。また、IAPだと、自動化できないようにわざわざ課金のダイアログを押せなくしていたりする。そういうのもサードパーティならではの悩みである。では UIAutomation 使えという話になるがそれはそれそれで、じゃあなんで appium とか calabash って開発されたんでしたっけという話になる。

次に、やれ selenium だ、appium だといっても中で書いているのは所詮スクレイピングである。出来上がるコードが元々辛い。ちょっとしたレイアウト変更でエレメントが取れなくなり、テストが失敗するのはよくある話だ。モバイルの場合、この上にさらにモバイル特有の例外処理を載せていくので最終的に本当に辛いコードになる。例えば端末のスペック差を吸収するため sleep を書きまくったりする。さらにきわまってくると、Android というのは本当にクソ端末多くて、突然 wifi が切れてテストが失敗したりする。ここまでくるともうどうしようもない。

追記

sleepせずにある要素が出るまで待ち続ける処理があるのでそれを使えば良いというコメントを頂きました。

確かにそうなのですが、私が appium を触っていた時はエレメント探索の関数が非常にバギーで使い物にならず、javascript のコード生で渡して実行させる手法を多用していました。この手法を使う限り sleep に頼らざるを得なかったのですが、今は状況が改善しているかもしれません。

そもそも受け入れテスト自動化に本当に向き合うなら、デジタルハーツやポールトゥウィンなんていう会社が世に存在する意味を真剣に考えるべきだ。そういった会社のテスターの練度は高く、例えば格ゲーなら格ゲーに知見のある人がいて、音ゲーなら音ゲーに知見のある人がいる。そういう人はテストの勘所がわかっており、仕様ドキュメントを渡すだけで綿密なテストケースを組んでくれる。コンピュータがそこまで追いつくのは何十年か先の話だろうと思う。また、画面を見てそれが正しい状態なのか間違った状態なのか判断させるのは、正直機械ではなく人間がやった方が手っ取り早い。属人性の極みみたいな所はあるが、現状を鑑みた上で現場でどちらか選べと言われたら正直人間のほうを選びたくなる。

まぁそんな調子なので、今は色々な障壁を乗り越える & メンテする覚悟があるとか、よっぽど何回も繰り返される部分のテストをターゲットにするとかすれば(こういう場合「殺虫剤のパラドックス」という言葉が頭をよぎるが)なんとか元は取れるかなという感覚でいる。もしくは、人間と機械の共存を模索し、完全自動化ではなく人間をサポートする役割にとどめるのが合理的ではないかと思う。

渋川剛気

本当に品質の高いプロダクトを作りたいなら、設計で地雷を踏まないのが一番良い。

ああきたらこう捌く、こうきたらこう捌くなんてというのを考えていたら下の下で、真に護身を身に付けた者であれば、もはや技術は無用であり、そもそも危機に近付くことすらできないのだと思う。