Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: Request specでresponse bodyのBOM付きCSVを検証する。

BOM付きのCSVダウンロード系の機能の検証をRequest specでresponse bodyのBOM付きCSVを検証する時に若干ハマったのでやり方をメモ🗒

BOM付きのCSVを検証する時の注意点

当たり前といえば当たり前ですが、encoding: 'bom|utf-8'を指定しないとパース時にエラー(Illegal quoting in line 1. CSV::MalformedCSVErrorのような)になるので注意が必要です。

stackoverflow.com

さらにパースできても以下のようにBOMが入っているのでkeyのマッチができなくなります。※ rows['column']が一見keyが一致しているように見えてもBOMによりnilが返却されます。

github.com

実運用ではエクセル等で文字化けせずに利用できて便利ですが、テストコードでBOM付きCSVを扱うのは大分大変です。

いい感じに検証する

上記の通りBOM付きCSVをそのまま扱うのは厳しいのでテストコードではBOMを削除して扱います。 response.body.delete("\uFEFF")でBOMを削除し、削除した文字列をそのままCSV.parseでパースして中身を検証しています。

describe 'GET /records.csv' do
  before { get records_path(format: :csv) }

  it '成功すること' do
    expect(response).to have_http_status(:ok)
  end

  it '適切なCSVが出力されること' do
    rows = CSV.parse(response.body.delete("\uFEFF"), headers: true).map(&:to_h)
    expect(rows.length).to eq 2
    expect(rows.last)).to eq(
      {
        'column1' => 'value1',
        'column2' => 'value2',
      }
    )
  end
end

※以下の通りBOMは容認されているが推奨されているものではんく削除によるリスクはほぼ無いものと判断しました。

UTF-8文字コードとしてASCIIを前提としたプログラムでもおよそ支障なく動作するように設計されているが、BOMによって正常に処理できなくなる場合がある。Unicodeの規格において、UTF-8においてBOMは容認されるが、必須でも勧められるものでもないとされている[5]。また、データベースやメモリにロードするデータなど、内部的なデータ形式では、プログラムの性能や効率の観点から普通BOMは用いられない。 バイト順マーク - Wikipedia

参考

qiita.com