とりあえずやってみればいいじゃん

とりあえずやってみればいいじゃん

エンジニア関連のことについてつらつら書くブログ

3/3 テスト可能なコードを書くということの2つの側面 #tryswiftconf

try!Swiftのセッションまとめシリーズです。Brandon Williamsさんの「The Two Sides of Writing Testable Code」についての記事になります。

資料

スライド共有サービスには上がっていないようです。try!Swift2017のslackの#slideには上がっている(しかもカンペ付き)ので、そちらをご参照ください。

内容

なぜテストをするのか

  • テストをやることによって潜在的なバグを見つけたりクラッシュを防いだりして時間を節約してきた
  • テストができるコードだけを書くようにしている
  • 関数的に書くことは良い試練になる
  • テストをドキュメント化してどう動くかの期待値を書く

ケーススタディ

  • 一見シンプルな関数でもテストをするのが難しいことがある
  • 例:ファイルを読んで内容を解釈していき、整数を返す関数
  • コンソールに出力することが要件だとすると、このためにデバッギングをしたりはしない
  • ディスクから読んだりするコードはよくあると思う
  • テストをする時は考えなければならないことがる
  • ファイル名を読まなくてはいけない場合
    • シンプルに見えるがnumber.txtだけでは済まない→/var/folders/…などのパスが必要
    • グローバル関数などが関わってきたりする
    • String(contentOfFile:)はハードドライブに依存する
    • 結果が他の世界の状態に影響する場合もある
    • コンソールをずっと見ているわけではないからわからない
  • なぜこの関数をテストするのが難しいか
    • 条件はハードドライブによって変わってくる
    • 特定のロケーションに置かなければならない
    • コンソールにメッセージが出されること、他の世界に悪影響を与えないことも確認しなければ
    • 入出力には明示的なもの、暗黙的なものがある

アウトプットのテスト

  • 副作用があるから難しい
  • 実行によって観測可能な変化が起こる
  • 実行の後の世界の状態を確認する必要がある
  • どうやって副作用をうまく扱うか
    • 副作用を境界付近に持っていく
  • compute関数
    • ログを出す代わりに(Int, String)の戻り値を返すようにしてみる
    • 副作用はロギングすることによって異なるチェーンの中でどう伝播していくかを考える必要がある

インプットのテスト

  • 食わせるデータは明確に定義できている
  • 関数を実行する際の状態がわからなければいけない
  • 協作用があるから難しい
  • アウトプットは影響のテストで、インプットは協作用のテスト
  • 協作用
    • 現在も継続的に研究されている
    • 定義
      • 実行をするために必要なもの
      • ある特定の世界の条件がなければ実行ができない

協作用が起こる場合のテスト

  • 同じ状態を作らなければならない
  • 1つのstructにすべてを入れてしまう
  • クッキーストレージはコントロールできる大きな協作用の一つ
  • シングルトンはテストしにくい
  • 日付は毎回違う値が返ってくるため大きな協作用になる
  • コード中でDateを使うと純粋な関数ではない
  • コントロールをするためにはプロトコルを入れて固定化する

  • 言語(話す方の言語)も協作用になる

  • どのような言語でもサポートしているアプリで自由にテストできるようになった
  • ReactiveSwiftをよく使っている
    • スケジューラを使ってやっている
  • UserDefaultsも協作用になる
  • 24かそれ以上の協作用要素がある
  • グローバル関数を1箇所にまとめてそこを通さなければいけないという状況を作れば楽になる

リファクタ

  • 1つめの原則
    • 成否だけを気にしていく
    • 関数の前にプロトコルを入れる必要がある
  • あるファイルからロードしたい場合は必ずこれを使うようにするというものを作る

まとめ

  • 影響と協作用の違いを説明
  • 影響のテストは実際にどう動くかより効果に注目する
  • 協作用の一つのグローバスstructにまとめて、それを通らなければアクセスできない状態を作る

Q&A

  • テストは前にやるのか後にやるのか
    • テスト駆動でよくやっている
    • バグレポートで失敗したテストを書き溜めてやる
  • 環境を注入するのにステートやモナドなど使うのか
    • 我々の環境はとても簡単
    • ギャップ環境はcoモナド
    • あまり考えずにやっている
  • プロパティのテストやったりする?
    • やりたいけど今のところやっていない

関連リンク

GitHub - kickstarter/ios-oss: Kickstarter for iOS. Bring new ideas to life, anywhere.

その他このトークに関する情報源

togetter

The Two Sides of Writing Testable Code #tryswiftconf - Togetterまとめ