2017年09月08日

MVCのModelとControllerの分離点と単体テストについての考え方

タイトルにすべて書いてしまってこれ以上言うことないんですけどね。
いや、みんなドライバ真面目に書いてテスト自動化してるの?
自動化は内的なI/Fでできる部分だけやって、他はやっぱり手動でEXCELとにらめっこじゃないの?っていうお話



そもそも仕様は変わるもの

こんな話をするようになったそもそもの原因は仕事なんだけど、仕事の話なんて大して面白くもないので自作ゲームの話しますね。
単体テストでテストケースうわーーーーって書いて仕様FIXするじゃん。
んで、しばらく動かして、やっぱ画面変えよう、例えばアイテム一覧はulタグじゃなくてtableタグで組もう、
あと
  • 食料 x 5
↑みたいに文字列でアイテム名と数量を混在させるんじゃなくて
アイテム名数量
食料5

↑みたいに表組みで表現しようとするじゃん
そうすると当然htmlアプリではjqueryに相当する部分が変化を起こす。
前者は

$("#item_1").text(model.items[key].name + " x " + game.items[key].count);

とかだったのが

$("#item_1_1").text(model.items[key].name);
$("#item_1_2").text(model.items[key].count);

になる。これはhtmlがC#になろうと一緒。MVCでいうところのController部分はView部分の変更に影響を受ける。
その影響を受けないようにするのがModelとControllerの分離なわけだ。

んじゃあ分離されたModelが自動テストの範囲なんじゃない?
んーちょっと変えたいなあ、と思うような画面仕様に引きずられてテストコード書き直しとか控えめに言って地獄ですよ
これが自分の趣味のプログラムならまあまだテストが散らかったなあ、で済むんだけど
仕事でやると考えるとあああ寒気がぁあああ(やっぱ仕事の話はやめよう)

ちなみに、これがおそらく誤解の元だと思うので強調するけど、自動テスト(UnitTest)と単体テストは別で、
Controllerは自動テストしないけどちゃんと単体テストはする。目視で。
UnitTest書かないとかいう話になるとUIは単体テストしないのかよとか言われるけどやるよ。目視で。
これもちゃんとやるにはselenimuとか使うんだろうけど仕様動いてる間は目視で。

そしてこの分解点、つまり画面の影響を受けて動きやすい部分をController
影響をうけず動きづらい部分をModelにわけると、MVC分離ってすごいきれいに別れると思うんですよ
特に悩むことない。あっUnitTest書きづらいなって思ったらその部分だけ切り離してControllerへ
ajaxとかのI/Oが絡む部分はControllerで情報を右から左へやりとりしてもらって、
情報の加工をModel側で実行すればよいのですよ

$.get((data)=>{
  model.next_scene(data);
});

↑な感じに。Controller部分はなるべく薄く。そうすると自動テストできる範囲が増える。

ログは面倒

これで解決といかないのが厄介なもので、どうしてもロジック中にI/Oが絡む部分がでてくる。それはログ。
異常発生時にコケました、はModelの関数からの出力でわかるからいいんだけど

  • 正常終了っぽいんだけどどっかで処理が止まってます
  • 異常終了でプログラムが続行できずどっかで死んでます
  • 処理は正常に動くんだけど異常に遅い。どこが遅延してるかわからない

みたいなのはトレースログ出し続けて様子見るしかないんだよね
かつて、こういうログはアスペクト指向で分離できるんじゃないかって幻想を持ってたんだけど
無事廃れました
結局アスペクト指向だって関数の前後に何か処理を挟むくらいしかできないんだよね。
やりたいのは関数内でどこまで処理が進んでるのか、どのくらい時間がかかってるのかなんだけど・・・

そう、関数内にオンデマンドで何かを書き込むってことは、I/Oが絡むのにModelから処理を分離できないのだ
ログをテストするのめんどくせぇえええ!!
まあ今は目視でやってますけど。目視で。こういうのlog4xで出力をパイプして単体テストするといいのかな?
何が王道なんだろう

ホワイトボックステストはできるだけやらない

ちなみにデバッガーでちまちま追っかけてすべての分岐を追うホワイトボックステスト
これはやりたくないでござる
EXCELにらめっこ目視と大して手間かわらないものをさして動かないModelで実施しなきゃいかんので苦痛
どうせその分岐、結合テストで通すんでしょ?

だからホワイトボックステストしなきゃいけないような関数内に大きな分岐を持つ構造にはそもそもしない
自動テスト可能なように、ifもforも浅くしといて細かく関数分割!ってのが大事だと思う

んでも込み入ったプログラム作るにはどうしてもホワイトボックステスト必要なんだよね。
特にマルチスレッド周りとか。きちんと動くか確証取りたいときはデバッガーでちまちま止めて同時実行させるし
まあマルチスレッドプログラミングもなるたけやりたくないよね。
posted by LoyalTouch at 09:16| Comment(0) | プログラム全般 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: