はじめに
先週の土曜日(2015年5月16日)に西脇.rb&神戸.rbで「Rubyistのためのテストコード相談会 ~テストの書き方に悩んでいませんか?~」という勉強会を開催しました。
この勉強会は「テストコードに関する疑問や悩みをみんなで持ち寄り、みんなで解決すること」を目的にした勉強会です。
勉強会中はいろいろと興味深い議論が出たので、今回のエントリではその内容を簡単にまとめてみます。
勉強会で挙がった質疑応答
よく使うフレームワークは?
- RSpecが大多数、Minitestが若干名。
- gemを開発するときはMinitest、RailsはRSpec、というように開発内容によってフレームワークを使い分ける、という人もいた。
Minitestってどうなの?
- 導入が簡単。assertメソッドだけ知っていればなんとかなる。
- Railsにも対応している。Capybaraも使える。
- RSpecのshared_exampleと同じようなことをしようとすると結構大変。
- minitest/specを使うとRSpecと同じような書き方ができる。が、それならRSpecを使えば?と思わずにいられない。
どれくらいテストを書く?
- 「どれくらい」という量ではなく、対象となるコードの重要性や複雑性の方が基準になる。
- 権限周りや課金周りなど、不具合が起きたときのインパクトが大きい部分は重点的にテストを書く。
- 手作業でのテストが面倒な箇所も自動化した方が楽。(アカウント登録時のメール送信など)
- そもそもテストがないとRailsのバージョンアップのときとかに死ぬ。
TDDやってる?(テストファーストしてる?)
- ものによる。毎回とは限らない。
- 作りながら仕様を考える場合や、テストの書き方が思いつかない場合は先に実装を始める。
- ただし、ある程度仕様やテストの書き方が見えたらゼロからTDDで作り直す、というアプローチもある。
- 入出力の振る舞いとテストの書き方が明確な場合はTDDで実装する。
カバレッジ(コード網羅率)って見てる?
- よく見てます = 1名
- simplecovっていうgemが便利。
- RubyMineのカバレッジ調査機能も便利。
- Railsをバージョンアップするときはカバレッジをよく見る。
- TDDで開発してたらカバレッジは100%になっているはず。
- カバレッジと一言で言ってもC1、C2など、いろいろな観点があるのでテスト技法の勉強もしておいた方が良い。
入力項目がたくさんある検索フォームなど、条件の組み合わせをすべてカバーしようとすると死にそうな数になる場合はどうしたら良い?
- 検索フォームであれば、全組み合わせをテストする重要性は低そう。
- ただし、権限管理や医療系のプログラムなどではあらゆる組み合わせを考慮しないと重大な問題が起きる。なので全パターンをテストする。
- デシジョンテーブル(組み合わせ表)を使うと組み合わせパターンを整理しやすい。
- rspec-parameterizedというgemを使うとデシジョンテーブルをそのままテストコードに落としやすそう。
- 複雑な処理であれば実装レイヤーを分離して別々にテストすると、効率よくテストが書ける場合がある。(例:「文字列を正しくパースできているか」「パース後の値で正しく処理できるか」で実装を分離する)
gemが提供している機能やRailsのバリデーションなどはgemやRailsを信頼してテストを書かない、というアプローチでも良いか?
- gemの機能をテストする必要はないが、アプリケーションに正しく組みこまれているか、というテストは必要になる。(例:before_actionで使われているか、等)
- ケースバイケースで判断すべきところも多いので、アプリケーションの仕様に応じて適切にテストを設計する必要がある。
privateメソッドもテストするか?
- 普通はテストしない。publicメソッドを適切にテストしていればprivateメソッドもテストできているはず。
- どうしても必要な場合は instance_eval 等を使ってテストする場合もある。
- エラー処理のように普通のテストでは実行しにくい部分はモックを使う。
モックやスタブはどんなときに使う?
- なんらかの理由で本物のプログラムが使えない、使わないほういい場合やわざとエラーを発生させたい場合に使う。
- 「モックを使った場合のコスト < モックを使わなかった場合のコスト」になる場合に使う。
- テストコードを実行する際、自分で制御できない要素がある場合に使う。
- Timecopのようなシステム時間を変更するgemもモックの一種。
- テストでモックを使いまくったら、本番環境で想定外のケースが大量に出てきて大変だった。(失敗談)
- 詳しくは 使えるRSpec入門・その3「ゼロからわかるモック(mock)を使ったテストの書き方」 を読む。
- Minitestでモックを使うときはmochaというgemを使うと便利。
Web APIが関わるコードのテストはどうすれば良いか?
- APIから大量のデータが返ってきて、それを処理するコードを書いている場合はVCRを使う。(主に参照系)
- 戻り値が単純な場合はモックを使う。(主に更新系)
モックやVCRを使っている場合、Web APIの仕様変更(不具合修正を含む)にはどうやったら気づけるか?
- APIがバージョン別のURLを提供してくれているのが理想。
- とはいえすべてのWeb APIがそうであるとは限らないので、Web APIの仕様をチェックするテストを独立して用意し、そのテストだけ本当にAPIにアクセスさせる、といった方法が取れるかも。(ジャストアイデアだけど)
本番環境とローカル環境では同じRDBMS(PostgreSQLやMySQL等)を使うべき?
- 同じRDBMSを使う人が大多数。
- ある程度の規模のアプリケーションになると、DB依存しそうなSQLやDB関数を書くケースも出てくるので最初から同じRDBMSを使う。
RSpecのit/specify/example/scenarioの使い分けが分からない
- どれもエイリアスの関係にあるので機能的には全く同じ。
- 文章として読みやすいメソッドを使う。(英語で書く場合に重要度が増す)
- 日本語ならexampleやspecifyで統一すると楽かも。(例: example "通知メールを送信する" do )
- 詳しくは RSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する や 使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 を読む。
Rakeタスクのテストはどうしてる?
- そのままだとテストしづらいので、メインロジックはModelに書く。Rakeはそれを呼び出すだけにする。
- rake_shared_context というgemを使うとRakeタスクのテストが書ける?(未確認)
Testで欠かせないgemは?
- capybara
- rspec-rails
- factory_girl_rails
- guard-rspec
- timecop
- database_cleaner
- email_spec
- poltergeist
- pry-byebug
- などなど。
オススメのデバッグ方法は?
- pry-byebugを使う。
- RubyMineならコードを汚染せずに好きなところでブレークしてデバッグし放題!
テストデータはどうやって用意する?
- FactoryGirlを使う、が大多数。
- ただしFactoryGirlは遅いのが難点。(なのでこの下にあるような高速化テクニックを使う場合がある)
テストスイートが大きくなって時間がかかる。どうしたらよい?
- 更新しないマスタデータはDatabaseCleanerの設定でtruncate対象外にしてデータ投入の頻度を減らす。
- テストのログレベルを変えてほとんどログを出さないようにする。
- 並列で実行するテクニックもあるが、予期せぬエラーが出そうな気もするので我慢する。
- 全テストケースの実行はWerckerやTravisのようなCIにまかせる。
- 300 examplesで10~15分ぐらいかかる。
- FactoryGirlやJavaScriptを実行するフィーチャスペックが特に遅い気がする。
Railsでよく書くテストのタイプは何?
- モデルが中心、という人が多い。
- 細かいテストはモデルスペックに、viewを含めたテストはフィーチャスペックにそれぞれ書いておくと結構安心できる。
テストコードがまったくないRailsアプリは何から手をつけたら良いか?
- 自分が関わってきたアプリ(仕様が分かっているアプリ)であれば、正常系の重要なユースケースのフィーチャスペックを書く。(例:新規アカウント登録や商品の購入など)
- 引き継いだアプリ(元の仕様がよくわからないアプリ)であれば、レガシーコード改善ガイド 等を参考にする。(Javaの本だけど)
レガシーコード改善ガイド (Object Oriented SELECTION)
- 作者: マイケル・C・フェザーズ,ウルシステムズ株式会社,平澤章,越智典子,稲葉信之,田村友彦,小堀真義
- 出版社/メーカー: 翔泳社
- 発売日: 2009/07/14
- メディア: 大型本
- 購入: 45人 クリック: 673回
- この商品を含むブログ (157件) を見る
テストコードはどれくらいDRYにする?
- 実装とは異なり、テストではDRYをあまり求めない方がベター。
- とはいえ、場合によっては shared_examples を利用した方が便利なときもある。
CI使ってる?
- 使ってる、が約半数。
- 失敗時の通知先はメール、Slack、Gitterなど。
- Wercker, Travis, Circle CI, Magnum CI, Jenkins, Side CIのようなツールがよく使われている。
- Side CIやCode Climateのように自動コードレビューしてくれるツールも便利。(うまくチューニングしないと山ほど警告が出る場合もあるけど)
Railsでモデルのバリデーションもテストしてる?
- テストする、が約半数。
- 単純な必須チェックとかはやらないが、条件付きのバリデーションや、正規表現を使ったバリデーション、独自に定義したバリデーションのテストはやる、という人もいる。
- 文字数のバリデーションなどはきちんと閾値(しきいち、つまり境界となる値)の前後をテストすべき。
- shoulda-matcherを使うと楽にバリデーションのテストができる。
まとめ
というわけで今回は「Rubyistのためのテストコード相談会」で挙がった質疑応答の内容をまとめてみました。
普段RubyやRailsのコードを書いている人は「あー、わかるわかる!」と思うような内容もいくつかあったんじゃないでしょうか?
よかったら参考にしてみてください!
懇親会はみんなでビアバッシュ!
謝辞
- 勉強会中は寺田さん(@aq2bq)に議事録を取ってもらいました。寺田さん、どうもありがとうございました。
- この勉強会は阪神深江にあるNilquebe(ニルキューブ)さんで開催しました。広くてキレイなのでとても快適に勉強会を開催できました。どうもありがとうございました。
西脇.rb&神戸.rbについて
西脇.rb&神戸.rbは西脇~神戸近辺で活動するRubyコミュニティです。
Ruby初心者の方、初参加の方も大歓迎ですのでお気軽にご参加ください。
「Everyday Rails - RSpecによるRailsテスト入門」も好評発売中!
「Everyday Rails - RSpecによるRailsテスト入門」はRSpecでRailsのテストコードを書くテクニックを初心者向けにやさしく解説した電子書籍です。
西脇.rb&神戸.rbの主催者であると僕とAkiさん(@spring_aki)が翻訳しています。