アヤオのレベリングキロク

日々のインプットをここでアウトプットします

【Rails】RSpecでjsonファイルを読み込んで保存するテストを書く

きっかけ

今回はjsonファイルを読み込んで、そのjsonデータを保存する実装をしていました。

RSpecも書くということでしたが(当たり前やん!)、jsonデータを読み込む時のやり方に少し躓いたので、まとめてみようと思います。

実装内容

  • 外部のファイルサービスに置いてあるjsonデータを取得する
  • その取得したjsonの中から特定のデータを今回作成した専用テーブルに保存する
  • この実装のRSpecも書く

という感じ。

RSpecを書くときは、外部ファイルサービスへのアクセスはしないでモックと/spec/fixtureに置いたファイルで対応する。

そもそもRSpec初心者の私には、 外部ファイルサービスにアクセスしないでテストする というのをどうしたらいいのかから悩む事になった。

モックを使うことを知る

こちらの記事を参考に直接外部ファイルサービスにアクセスしない方法が見えてきました。

qiita.com

ここで私が使ったのは、1番よく使われるらしい double メソッドと allow メソッド。

jsonを読みにいく処理が走るときは、/spec/fixtureに置いたjsonファイルの中身を返すというように書きました。

例えば、こんな前提

  • userに対するscoreが保存されているjsonデータが外部ファイルサービスのバケットにある
  • バケットにコールするモジュールがCallBucket
  • データを保存する処理はStoreJsonDataにかかれている
  • CallBucketStoreJsonDataの中から呼ばれる
  • テストはStoreJsonDataで保存されたsocreが正しいかを確認する
  • sample.jsonにはとあるuserのscore=3というデータがあるとする

これをテスト書いてみる

let(:json_file) { Rack::Test::UploadedFile.new("#{Rails.root}#{file_path}", "application/json") }

before(:each) do
    bucket = double('bucket')
    json_data = JSON.parse(File.read(json_file.path))
    allow(CallBucket).to receive(:new).and_return(json_data)
    StoreJsonData.new.import(bucket)
end

context "sample data" do
    let(:file_path) { "/spec/fixtures/sample.json" }
    it "save" do
      expect(user.score).to eq 3
    end
end

詰まったところ

JSON.parse(data) としていますが、最初は JSON.load(file) としていて、rubocopにセキュリティ的によくないよ!と怒られました。

ただ、単純にJSON.parse(file) ではだめで、一回オブジェクト化した状態で JSON.parse を使わなければならないことに少し時間がかかりました。

before/afterはこんな感じ

before

json_data = JSON.load(json_file.path)

after

json_data = JSON.parse(File.read(json_file.path))

JSON.parseにはファイルの中身をロードする処理はないので、事前にfile.readしてjson文字列として渡してあげないといけないということらしいです。

さいごに

まだまだRSpecは勉強中ですが、次からファイルの読み込みが必要なRSpecはすぐに書けそうです!

でも全体的にRSpecの知識が足りてないから、一回体系的にやりたいところ。。

時間を見つけてコツコツとキャッチアップできればと思います。