Wondershake 開発者ブログ

LOCARI(ロカリ)の運営会社の開発者ブログです。

LOCARI のテストで気をつけてること

この記事は Wondershake Advent Calendar 2日目の記事です。

先日分は間に合わなかったみたいですmm 代わりに謝罪しておきます 🙇

普段 RailsLOCARI のサーバーサイドを主に書いている mmyoji です。やっていきます。

話すこと

  • LOCARI のテストどーなってんの
  • 自分がテスト書く時に気をつけてること

Wondershake(LOCARI)のテスト環境

現在 Wondershake で一番コードベースが大きいプロジェクトが LOCARI という女性向けのメディアサービスのサーバーサイドを含む Rails アプリになってます。自分は最近までフリーランスだったのですが、ほとんどの現場でテストが書かれていませんでした。が、こちらは Coverage 85% 強となってて、比較的安心して開発が進められる環境となってます。(「低い!」と思われる方、幸せですね 😇 )

現状 Rails アプリはいくつかありますが基本的にすべて RSpec を使っています。 LOCARI に関して言えば本当は MiniTest 使いたいなーという意見(主に自分)もありますが RSpec のコードが結構沢山あってなかなか踏ん切りがつかないという状況です。

あと LOCARI アプリに関しては独特で以下の例でも見られると思いますが、 MiniTest に寄せたい思惑からか、expect ではなく assert を使って書いてたりします。このキモい感じが僕は割と気に入ってます 😈 ❤️ (読みづらいかもしれませんがご了承ください...)

で、本題に入りますが普段テスト書いてて気をつけてることとかを雑に書いていこうと思います。

こんなことを気をつけてます(個人的に)

賛否両論あるかと思いますがご容赦ください 🙇 あくまで 僕個人 が気をつけていることになりますmm

  • vcr ガンガン使う
  • 極力 example をまとめて test の実行速度を速くする
  • 意味が被るようなテストコード書かない
  • let(!)before を正しく使い分ける

vcr ガンガン使う

まず vcr の説明を簡単にしておくと、外部 API との通信を yaml ファイルにダンプしておいて、1回目以降はそちらのファイルを参照して実際に通信したかのようにテストを実行してくれる便利なライブラリです!

外部の API と通信を行う際に stub で済ませちゃうこともあると思うんですが、結構ガシガシ vcr に任せてしまいます(なので spec/cassettes が結構膨れてます...)

ただそうすることで少なくとも一回は実際のリクエストをテストできるので、例えば「ドキュメントに書いてあるレスポンスと違った!」みたいなことが防げたり、安心感があります。

あと小手先ですが、生成されるテストデータが微妙に異なるせいで、リクエストに含むパラメターが変わり、 vcr がうまく動かない(「異なるリクエスト」として扱われてしまう)こともあるので、そういう時は match_requests_on オプションを活用しています。このオプションに関しては以下を参考にしてみてくださいmm

以下のようなオプションの付け方してる箇所が多いイメージ

describe '#notify', vcr: { match_requests_on: [:host, :method] } do
  specify 'requests to external API' do
    # 処理
  end
end

極力 example をまとめて実行速度早くする

「どこでテストが落ちたのかわかりづらい!」と言う人もいるのでデメリットも多少ありますが、テストの初期化コストが大きく、且つまとめてしまえる場合などは特に example をまとめてしまう方がテスト実行時間減らせてオススメです。

API テストの例(あまりいい例ではないです。色々と省略)

# Before
describe 'GET index' do
  before do
    api_request
  end

  # HTTP status code と response の中身をそれぞれ別 example でチェックしている

  specify do
    assert_resposne 200
  end

  specify do
    assert_json_match(matcher, response.body)
  end
end

# After
describe 'GET index' do
  before do
    api_request
  end

  specify do
    assert_resposne 200
    assert_json_match(matcher, response.body)
  end
end

実際にベンチマーク取ってどれだけ速くなってるか、みたいなの出したかったですすいません

意味が被るようなテストコード書かない

「A がチェックできてたら B は保証されるから無くていいよね」という話です。

ある程度テスト書いてる人からすれば当然のことかもしれませんが、プログラミング書き始めた頃はよく指摘されてたので今でも意識してます。なんでもテストしたがる病ですね。

let(!) と before を正しく使い分ける

これは RSpec 特有の話になってしまいますが、RSpec 使い始めだとなんでもかんでも let(!) で書いちゃう人が一定数いると思ってて、テスト読む際に自分は意識して使い分けてます。

  • let! : example などで1回以上参照される
  • before : example などで参照されない

要するに let! に書いてあれば example 内で参照されたり、値をチェックしてたりするのでテストコード読む際に判断がしやすくなります。逆にそうでなければ before ブロックは読み飛ばして example だけ読めば大体わかるので無駄な時間使わずに済む、ということになりますね?(無理やり)

まとめ

テストはしっかり書きたいけどビルドが長いのは嫌だ、という気持ちを少しでも緩和するためこれからもやっていきます。

あと他の方のテストに関する気遣いを聞きたい今日この頃。

明日は Android エンジニア兼 PO/PM の shirokura です。ちゃんと書いてくれるかな? 😏