本来やりたかったこと
DB分割前提のテストを書きたいので、FactoryGirlを拡張して、シャード指定できるようにしたい。
ちなみに分割はOctopusを利用した水平分割です。
FactoryGirlにシンタックスを追加する方法
概要
方法は色々ありそうですが、今回は、FactoryGirl::StrategySyntaxMethodRegistrar
を利用します。
非公開APIっぽいのでメンテナーにはあまりいい顔されないかもしれません。
例として、テストコードを書いてるときに🍣が食べたくなった時を想定してcreate_sushi
を追加します
コード例
spec/support/factory_girl_ext.rb
class SushiSyntaxRegistrar < FactoryGirl::StrategySyntaxMethodRegistrar
def define_strategy_methods
define_sushi
end
private
def define_sushi
strategy_name = @strategy_name
define_syntax_method("#{strategy_name}_sushi") do
Rails.logger.debug "🍣"
end
end
end
sushi_create_syntax_registrar = SushiSyntaxRegistrar.new(:create)
sushi_create_syntax_registrar.define_strategy_methods
spec/models/sushi.rb
RSpec.describe Sushi, type: :model do
it "looks like 🍣" do
expect(create_sushi).to be true
end
end
テストを実行するとログに🍣が表示されています。やったね!
ちょっとだけ解説
- デフォルトだと
spec/support/
配下は読まなかった気がするので、spec_helper.rb
辺りでrequireしてあげてください -
FactoryGirl::StrategySyntaxMethodRegistrar#initialize
の引数は定義するシンタックスに利用されます。- 今は
:create
を引数にしてcreate_sushi
を定義していますが、:build
を渡せばbuild_sushi
も定義することが出来ます
- 今は
-
FactoryGirl::StrategySyntaxMethodRegistrar#define_syntax_method
は、FactoryGirl::Syntax::Methods
に対してメソッドを追加するメソッドです。もし、すでに定義されてしまっている場合はModule#undef_method
してしまうので、create
を定義すると後勝ちでcreate
が全て🍣メソッド化します
本来やりたかったことの解決
- 要するに便利なdefine_methodを呼んでいるようなものなので、上の
define_sushi
のように今回は以下のようなコードを書きました - 以下を実行すると、
create_with_shard :model_name, :shard1
のようなシンタックスが生まれます
def define_singular_strategy_method_with_shard
strategy_name = @strategy_name
define_syntax_method("#{strategy_name}_with_shard") do |name, shard, *traits_and_overrides, &block|
Octopus.using(shard) do
FactoryGirl::FactoryRunner.new(name, strategy_name, traits_and_overrides).run(&block)
end
end
end
まとめ
- FactoryGirlにsyntaxを追加する方法でした。