私は、テストフレームワークの中でも、とりわけRSpecが嫌いです。
不思議なドメイン言語を覚えなければいけないところや、テストを読み下すときに脳のメモリを余計に使うところ、書き味の悪さや周辺エコシステムの複雑さ、またRSpecの界隈に集まっているエンジニアの雰囲気が苦手というのもあって、Railsと同じぐらい、使わなくて済むならば使いたくないと感じているフレームワークです。

しかし、Railsで飯を食べている以上避けることができないのもまたRSpecの嫌な所で、いやいややるので一切覚えることができず、毎回あらゆることをGoogle先生にお尋ねしながら開発を進めています。

そんな中で、解決するのに手こずった内容があったのでメモしておきます。

モデル同士のアソシエーションのRSpec

「こんなのやる意味あるのか?」と私は思うのですが、どうやらアソシエーションが設定されている事を確認するSpecを書きたいという要求があるようです。
やる意味あるのか?と思ったのはあながちおかしくないようで、それをやっている例があまり出てきませんでした。
具体的にはこんな風に書きます。

RSpec.describe SampleModel, type: :model do
  describe 'References' do
    it { is_expected.to belogs_to(:hoge) }
    it { is_expected.to have_one(:fuga) }
    it { is_expected.to have_many(:piyo) }
  end
  #...
end

has_many/has_oneでアソシエーションを設定するのに、Specではhave_manyでチェックしないといけないところはややわかりづらいですね。

ActiveStorageでアップロードを伴うSpecを書く

画像のバリデーションを用意しているとかで、ファイルをアップロードして、それに対するバリデータの動きを見るようなSpecを書く場合です。
StackOverFlowにはごっついアップロードコードを用意しろという回答が出てきますが、fixture_file_uploadというメソッドを使えば、それよりは簡単に書くことができます。

#sample.imageのimage部分がActiveStorageで関連付けられたモデルだと思ってください
context '...' do
  before{ sample.image = fixture_file_upload('/images/100x100.png')
  it { ... }
end

ここで、アップロードするファイルはspec/fixtures/imagesディレクトリ配下に配置します。
fixture_file_uploadのrootディレクトリがspec/fixturesになる訳です)

ActiveStorageを使ったspecをCircleCIで走らせるとエラーでコケる

具体的に出ているエラーは、こんな具合のものです。

Errno::EEXIST:
  FIle exists @ dir_s_mkdir - /home/circleci/...

上記のエラーでネットを探すと、Windowsのディレクトリ名の扱いに関係したページばかりが出てきますが、原因は別の所にあります。
これは、ActiveStorageの保存先を設定するときに、storage.ymlに

local:
  service: Disk
  root: <%= Rails.root.join("/public/images/active_storage") %>

などと設定している場合で、サーバの構成の都合上、/public/imagesがシンボリックリンクに設定されているような環境で、なおかつCircleCIが利用する環境向けの設定ファイル(例えばenvironments/test.rb等)に

config.active_storage.service = :local

と設定してあるケースで発生します。
手元ではシンボリックリンクが活きているのでエラーになりませんが、CircleCI上に上げたとたんにシンボリックリンクが使えないものになっているので、このエラーになるというわけです。

解決方法としては、(どうせCircleCI上のコンテナは使い捨てなので)storage.ymlにシンボリックリンクでないディレクトリを使うストレージの設定を用意して、それを使うようにします。

具体的には

local:
  service: Disk
  root: <%= Rails.root.join("/public/images/active_storage") %>

cci:
  service: Disk
  root: <%= Rails.root.join("/tmp") %>

等とCircleCI用のストレージ設定を用意しておいて、環境別の設定の方にも config.active_storage.service = :cci として、専用の設定を使うように記述してあげれば良いです。

まとめ

RSpecのように、テストを書くのが面倒なフレームワークを使っていると、テストを書くこと自体が億劫になって、結果としてプロダクトの品質に負の影響を及ぼす事になると感じています。

私のこれまでの経験から、プロダクトは生き物なので、下手に秘伝のソースを継ぎ足して構築していくよりも、部分的にでも刷新し続けられる状況を保つようにするべきと感じます。

刷新作業の際に、勇気をもってプロダクトにメスを入れられるようになるためにも、テストを書きやすく、保守しやすいフレームワークが求められていると感じます。