気が向いたらそのうちサンプルコードとか付けてちゃんと書きます. 向かなければそのままです.
- ドラッグ&ドロップには色々な要素が絡んでくる
- バグが入り込みやすい
- どうテストしたら良いか? / どうバグを再現したら良いか?
- 「なんかある操作をしたらバグったはずだけど, 同じようなことをしているはずなのに再現しない」
- 例として iOS のアプリケーションアイコンの並び替えのような UI を考えます
- 「アイコンをドラッグ&ドロップで移動」を分解してみる
- アイコンをドラッグする
- ドラッグ中のアイコンはタッチ座標についてくる
- その他のドラッグしていないアイコンは, ドロップ後にどうなるかのプレビューを表示する
- ドロップすると移動を確定する
- アイコンをドラッグする
- さらに技術的な要素を混ぜつつ分解する
- ドラッグを開始する
- ドラッグ中のフラグが立つ
- アイコンをドラッグする
- タッチ座標にドラッグ中アイコンの座標を設定
- ドラッグ中以外のアイコンは, タッチ座標から並び順 (プレビュー) を計算
- 並び順 (プレビュー) を元に, ドラッグ中以外各アイコンの座標を設定
- ドロップすると移動を確定する
- ドラッグ中のフラグは消える
- 最後のタッチ座標から並び順を計算
- 並び順を元に各アイコンの座標を設定
- ドラッグを開始する
- (補足: 実際に画面上の指定した座標にアイコンを表示するのは UI フレームワークの役目となるので, ここでは扱わないことにします)
- 分解した内容に注目すると
- 1, 2, 3 は発生するイベントごとに分けられている
- 2b と 3b, 2c と 3c はほぼ同じ (であるべき) なので, 共通の処理を使い回せる
- 2a, 2b (3b), 2c (3c) の入出力は以下のようになっていて, イベントそのものとは独立している
- タッチ座標 → 表示座標
- タッチ座標, 元の並び順, ドラッグ中のアイコンの ID → 並び順
- 並び順 → 表示座標のセット
- これらの分析から, 以下のようにテストを分割できる
- ドラッグ開始イベントでドラッグ中フラグが立つ
- ドラッグイベントでタッチ座標が「後続の処理に渡る」
- ドロップイベントで, ドラッグ中フラグが立っていれば
- ドラッグ中フラグが消える
- タッチ座標が「後続の処理に渡る」
- 前述の 2a, 2b, 2c それぞれのユニットテスト
- イベントに強く関連する部分と, イベントとは独立な部分を分けたのがポイント
- 2b はさらにタッチ座標を「離散化」する部分を分けると良い
- 大抵の場合, ピクセル単位のタッチ座標は, 並び順の計算に対する入力としては幅が広すぎる
- アイコンの大きさ (+ margin とか) で離散化する部分と, 離散化した座標を使った並び替えの計算に分けると, コードの見通しも良くなり, テストも書きやすくなる
- というわけで無事 / 適度な粒度でユニットテストを書くことができるようになりました
- バグったときも再現実験をコードで行うことができる