2019年12月17日火曜日

fixture_file_upload を使うと他のテストがエラーになる

遭遇した現象

ActiveStorageを使っているプロジェクトで、fixture_file_upload を含むテストを追加したら、
関係ないはずの他のテストがランダムに失敗するようになった。

追加したのはこんな感じのテスト。

      test "create with valid file attachment" do
        image_file = fixture_file_upload("test/fixtures/files/sample.jpg", "image/jpg", :binary)
        post somethings_path, params: { something: { name:  "新規作成",
                                                     image: image_file } }
        assert_response :created
      end

失敗時のエラー

NoMethodError: undefined method `column_types' for nil:NilClass
  • 常にではない。成功するときもある。
  • fixture_file_upload を含むテストをコメントアウトすると、常に成功するようになる。
    コメントアウトを戻すとまたランダムに失敗する。
  • ActiveStorageの代わりにCarrierWaveを使っているプロジェクトでは、発生したことがない。(Railsのバージョンは同じ)
  • content_type をチェックするようなバリデーションがあるので、そこで失敗していそう。

解決策

下記Railsガイドを参考に、アップロードしたファイルをクリーンアップする処理を追加。
Active Storage の概要 - 11 結合テスト中に保存したファイルを破棄する

remove_uploaded_files.rb というファイルを作って、

# コードはRailsガイドより引用
module RemoveUploadedFiles
  def after_teardown
    super
    remove_uploaded_files
  end

  private

    def remove_uploaded_files
      FileUtils.rm_rf(Rails.root.join('tmp', 'storage'))
    end
end

module ActionDispatch
  class IntegrationTest
    prepend RemoveUploadedFiles
  end
end

テストのファイルで require

require "test_helper"
require "remove_uploaded_files" # この行を追加

そうすると、発生しなくなった。

何が行われている?

追加したコードにより、テストの実行後に、 tmp/storage ディレクトリが削除されている。

Railsガイドの解説にある以下のエラーが発生していたのではと思われる。

このコールバックを実行すると、テスト中に作成されたすべての接続を確実に完了するので、Active Storageでファイルが見つからないというエラーは表示されなくなります。

ちなみに、テスト実行時にストレージとして使用するフォルダの設定は config/storage.yml にある。

Active Storage の概要 - 2 セットアップで設定した部分。

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %> # これ

amazon:
  service: S3
  access_key_id: ""
  secret_access_key: ""

この設定を他のディレクトリにしているときは、 remove_uploaded_files.rb 内の、クリーンアップするフォルダの指定も合わせて変えないといけないはず。

    def remove_uploaded_files
      FileUtils.rm_rf(Rails.root.join('tmp', 'storage')) # ここ
    end

環境

Windows 10
Ubuntu 18.04.1 LTS (Windows Subsystem for Linux)
Ruby 2.5.3
Rails 5.2.3

参考

How do I test a file upload in rails?
色々調べているうちにこのページを読んで、どうやらRails5のActiveStorageを使う場合ではやり方が違いそう?と思ってRailsガイドを読み直した。

0 件のコメント:

コメントを投稿