iOSエンジニアといいかんじなテストの話

Consumer Service Engineer MeetUp Vol.1 ~iOS編~ - dots.

に行った。

最近あんまりザ・iOSアプリ開発らしいことしていなかったので情熱的な各社の話を聞けておもしろかったし、意識の高まりを取り戻せてよかった。

時間なかったので感想書く余裕ないかと思っていたんだけど、http://ainame.hateblo.jp/entry/2014/04/25/014605 の感想なんかを読んでたら触発された。

人力テスト

自動テスト vs 人力テストの構図というよりは、デベロッパーテスト、品質管理とユーザーテストやユーザビリティテストの違いで理解していた。
テストの目的と観点、誰が何をテストするのかという部分に注目するとスッキリすると思う。
講演した各企業の担当の人はユーザビリティテストに積極的だが、デベロッパーテストはうまくいってないという話を確かにしていた。

前述のエントリで問題としているのは人力のデベロッパーテストに頼らざるをえないという部分だと思う。
デベロッパーテストは通常自動化した方が好ましい。が設計をうまくテスタブルにする必要がある。View Controller盛らないとかもその一部である。
すでにうまくいってない設計で数年稼動し続けている場合、リファクタリングを施すか外からの受け入れテストの自動化で補うという方法がある。受け入れテストの自動化はたいていハードルが高い。よってうまくいってない設計のコードを抱えた開発現場ではテスト自動化にあまり手を出せずに、テスターによる人力のデベロッパーテストにリソースを振らざるをえないという現状があると思っている。

ちなみに設計うまくいってないというのは普通だと思う。むしろうまくいってるのを見たことがない。iOSAndroid向けのモバイルアプリケーション開発の歴史が浅く知見がないのとプラットフォーム自体の変化が激しいのが主な要因かとおもう。まだしばらくは作って壊して直して段々いいかんじにしてゆくというのを繰替えしていくしかなさそうだ。

ユーザビリティのテストは自動化は困難だ。だが逆に手動なら人件費さえあれば取り組むことは容易。

歴史的経緯によりテスト自動化がなされていない(IDEのサポートがない時代は厳しい感じだったので普通)既存の運用されているアプリケーションのデベロッパーテストの自動化に取り組み現状を打破したい場合、よい感じのエンジニアが政治力を発揮ししくみごと変えてしまう、というパターンが必要かと思う。

WebAPIに依存したテスト

自分はWebAPIとの通信をひとつのClientクラスにまとめて、そのオブジェクトをモック化するようなやり方にシフトしつつある。
なのでなんでもかんでもHTTP通信の絡むテストをHTTPレスポンス専用のスタブ化ツールでこなすということはなくなり出番が少なくなっていっている。
ただしリクエストオブジェクト自体の中身の検証(パースとか)が必要な場合OHHTTPStubsのようなツールを使うのは以前有効だと思う。

非同期処理を含むテスト

KiwiやSpectaのような高次なテストフレームワークに頼るのが一番楽な方法だけど、SentestingKit/XCTestをそのまま使わざるを得ないケースも結構あってそういう時に絶対これを使った方がいいという定番のものがない状態。
みんなフラグやらセマフォやらとuntil loopブロックで完了待つ処理を、それぞれ良さそうな記述方法を模索しているような段階っぽい。
個人的にはAppleが将来SentestingKitサポート切ったあたりでXCTestに非同期処理のテスト用のインターフェイスを入れてくるんじゃないかなーと予想している。

テストダブル

OCMockを使ったブログサンプルとかをみてるとモックオブジェクト化してるものの何をテストしているのかよくわかないコードが結構ある。モックライブラリのAPIを知るにはいいかもしれないけど、どう使うかという部分で実践的な使用例はもうちょっと足りないなあ、と思っていた。

「ロールをモックせよ」をチェックすることをおすすめしたい
http://jmock.codehaus.org/oopsla2004_ja.pdf

ViewController

ViewControllerはMVC-Viewの一部でもあると思っている。

ウェブエンジニアにView Controllerの役割を説明する時の図

<html>
<body>

<!-- storyboard/xib -->

<script>
// View Controller
</script>
</body>
</html>

またMVCアーキテクチャは実装したクラスをM-V-Cのどれかの箱に入れる作業ではないという考えを持っている。
あくまでデザインパターンを対象のプラットフォーム応じて適用していく為の考えという感じで、たとえば前述のViewControllerなんかは典型でViewのロールで振る舞ったりControllerを実現したりと横断的な存在だ。正直ややこしい。

ウェブエンジニアのテスト意識 > モバイルアプリエンジニアの其

モバイルアプリのテストはウェブアプリケーションでいうとJavaScript部分のテストに近い。
テスタブルに書かないとそもそもテストできないし単体でテスト可能な部分と結合したレベルで行った方がいい部分を見極める必要がある。と考えるとそんなに違いはないと思っている。
がウェブアプリケーションフレームワークのがデフォルトプロジェクトテンプレートによってロジック専用のクラスとテストを生成してくれたりするのでその部分は傾向が出易いかもしれない。iOSアプリケーションだとUI非依存なクラスを作る意識を自発的に作っていかないといけないし。

受け入れテスト

ユーザーインターフェイスの振舞いのテストは受け入れテストツールでする。
よく「ビューのテスト」という言葉が登場すると思う。これが発言者にとって何を意味するのかはすりあわせた方がいいと思う。
スクリーンショットの差分をチェックするようなツールがこれが有効に作用する場面というのも限定的だ。

回帰テスト

テスト自動化に取り組んでないならいますぐ行うべきメリットがあるのが「不具合の修正時には必ず先に不具合を再現する自動テストを書いてから修正する」だと思う。

不具合にテストを書いて立ち向かう - t-wadaのブログ

デバッグ実行しながら「原因」をつきとめる→原因を再現させるコードに落すことにする。これはユーザー目線の受け入れテストで自働化やらないといけないというものでもなくて、原因の一番深部の部分の処理という限定的なテストでまずはよい。

たとえばiOSアプリだと「この状況の時このオブジェクトにこの値が入ってる時にこのメソッドの返り値がnilになる」→そしてそれが全部ViewControllerに書いてある。というのがよくあると思う。そうするとユニットテスト化は無理かーとかいってあきらめてしまうことが自分はよくあった。

しかし、この時に諦めずに「メソッドの返り値がnilになる」状況だけを起せる疑似コードをテストケースにコピペして欲しい。コンパイル通らない部分はコメントアウトしていい。

こうしても元のViewControllerとは一切関係ない無駄なテストができるのでは? と思うかもしれないけど。まずテストが書けるということが重要で。書いたらどうすればテストが書けるようになるのかという部分が理解しやすくなってくる。これは経験的に長期的な設計方法の改善に役立っていると感じるのでおすすめしたい。

クソコードに飛び込むためのテスト

回帰テストの項目とよく似ているけど、コードの詳細設計や仕様を誰も把握していない+読んでもよくわかないコードに立ち向かわないといけない時にテストが役立つ(しばしば自分が過去に残したコードだったりもする)。これは理解するためのテストになる。

具体的にはデバッガとともにアプリを立ち上げステップ実行しながらlldbコンソールなどでフームと値を評価しながらアプリの動作に問題なければ、その試した内容を仕様として理解してテストコードに落しこむという作業になる。これをやると既存のコードを理解しつつ改修する、みたいな時に助力になるということに最近気付いたのでよくやってる。

人力テスト is NOT Dead

プログラマ美徳とかの耳心地の良い武勇伝などもあって自働化を賛美するあまり、手動操作でのテストの価値を不当に貶めているように感じている。

受け入れテスト自動化に取り組む時にありがちなのが自動化できなかった場合に、そのテスト自体を断念してしまうことがあった。これはあまりよくない。というかせっかくテストケースとかシナリオとかして文章化したのだから管理した方がいい。典型的なシステム開発現場のようにMSエクセルでキッチリ表つくる必要はなくて行リストを書き留めて、他人が再現可能な感じにしておくだけでもいいとおもう。

これは自働化されたユニットテストとはまったく性質が違うものだから、実行するサイクルはゆるやかなものでいい。優先度を設定してリリース前に範囲を決めてザットやる、とか。

まとめ

なんか文章がえらそう