幸せでもAPIは叩かない、RSpecでのテストづくり
「Happy Elements Advent Calendar 2023」 12月21日の記事です。
初めまして、Happy Elements カカリアスタジオの新規タイトル開発チームで働いているardririyです。
学生アルバイトとして今年の秋に入社し、業務では主に社内ツールのテスト作成をしています。社内ツールはRuby on Railsによって書かれているのでテストも勿論Rubyで書いているのですが、実のところRubyはプログラミングをはじめたてのころに少しだけ触って以降ほとんど書いていなかったので、毎日試行錯誤を重ねながら楽しんでいます。
業務のコーディングに触れた感想ですがGitHub CopilotやGPTをうまく業務に取り込んでいるな、と感じています。Rubyについてはわからないことばかりでなので、文法がわからなくて書いてあることが読めなかったり、コードを書く際に実現したいことを愚直に書こうとすると読みづらくなるが実はある記法を知っていれば簡潔に書けた、といった問題が少なからず発生します。こういったコーディング上の問題は生成系AIを使えば解決できることが多いので、利用環境があるのは非常にありがたいです。
はじめに
社内ツールのテストではRSpecを利用しているのですが、テストを書く際は対象クラスのAPIを叩かずにモックを作成してくださいと指示をもらっており、それに従って作成してきました。今回は、なぜAPIを叩かないのか、どのように実装すればいいのかを書いてみようと思います。
RSpecとは
RSpecはRubyで利用できるテストツールです。
細かい説明は割愛しますが、例えば
expect(10 - 2).to eq 8
で、10 - 2
が8
と等しくなることを期待する、といったようなテストが書けます。英語の構文に近く、とても書きやすくなっています。
APIを叩かないのはなぜか
テストの独立性に欠けるからです。
テスト時にAPIを叩いている場合、通常時には問題なく動作しますがAPI側で障害が発生したり、仕様が変更されたりした場合にテストが通りません。そうなると、コードが原因でテストが落ちているのかAPIが落ちているのかの判別がつかず、疎通状態の確認などの二度手間が発生してします。
テストではAPIを叩かない場合、APIが落ちていてもテストは通るので疎通状態の確認をするまでもなくコードに問題はない、反対にテストが落ちていればコードに問題がある、というように問題の切り分けが簡単になります。
反対に言うと、このような切り分けが出来ないとテストとしてはあまり良くない、ということですね。
他にも、以下のような理由が考えられると思います。
- テストはかなりの回数を回すことになるので、外部APIを叩くのは迷惑
- 通信が挟まるので、その分実行速度が落ちる
どうテストする?
実際のコードでは、APIを叩いたかのような動作をするモックを作成しています。
例として、全ユーザの情報を取得するAPIを利用して、そのAPIを使ってユーザ名の名前の配列を作成するメソッドを考えます。以下のコードの、usernames
メソッドがテスト対象です。
class UserClient
def self.fetch_users
# 全ユーザの情報を取得
response = RestClient.get("http://api.example.com/users")
JSON.parse(response.body)
end
def self.usernames
users = fetch_users
users.map { |user| user['name'] }
end
end
この場合はユーザの情報を取得して、ハッシュに変換するfetch_users
メソッド全体をモックにします。
let(:users) { [{ 'name' => 'John' }, { 'name' => 'Jane' }] }
before do
# UserClientクラスのfetch_usersメソッドが呼び出されたら、上で定義したusersを返すようにする
allow(UserClient).to receive(:fetch_users).and_return(users)
end
it "ユーザ名の配列を返すこと" do
expect(UserClient.usernames).to eq(%w[John Jane])
end
実際のAPIは名前に限らず、例えばユーザ名やメールアドレスなどの情報を含んでいるかもしれませんが、今回のテストでは名前以外の情報に興味がないので、必要な値のみを含むハッシュを返しているのがポイントです。
このようにテストを書くことで、APIの状態に関わらず作成したコードが正しい値を返すか、すなわち正常に動作しているかをテストすることができます。
まとめ
テストを書くときは、どれだけ幸せでもAPIは叩かないようにしましょう!
Discussion