Railsのmodelでprivateメソッドのロジックをテストしない

みなさんはRailsのモデルでprivateメソッドをテストしますか?

僕はしません。

理由はpublicメソッドではないからです。

Privateメソッドをテストするって理由の一つが、「privateメソッドのロジックをテストしたい」だと思います。

ふーん、でもそのロジックはそのモデルにあるべきなんでしょうか?そして、そのモデルでテストするべきなのでしょうか?

他のモデルで同じロジックを使いたいときはどうするのでしょうか?

Railsにはconcernという機能がありますが、僕は基本使わなくなりました。

なせ?単純にいらないからですw

嘘です、必要です。そもそもconcernの存在意義が、ロジックを共通化するものではないというだけです。

では、どうするのか?

そのロジック用のモデルを作成することで解決できます。

具体的にやってみましょう。

Humanモデルにロジックを書いてみる

class Creature
  include ActiveModel::Model
  include AcitveMode::Attributes

  attribute :name, :string
end

class Human < Creature
  private

  def hello
    "Hello #{name}!"
  end

  def hi
    "Hi #{name}!"
  end
end

hellohi メソッドをテストしたいよね?

でも、privateメソッド、、

ならば!

Greetモデルを作成してみる

class Human < Creature
  private

  def greet
    @greet ||= Greet.new(creature: self)
  end
end
class Greet
  include ActiveModel::Model
  include AcitveMode::Attributes

  attribute :creature

  def hello
    "Hello #{creature&.name}!"
  end

  def hi
    "Hi #{creature&.name}!"
  end
end

どうでしょうか?

これでprivateメソッドのテストは不要になりますね。(Greetモデルのテストで担保するため)

さらに移譲してみましょう。

class Human < Creature
  delegate :hello, :hi, to: :greet

  private

  def greet
    @greet ||= Greet.new(creature: self)
  end
end
irb>human = Human.new(name: 'murajun1978')
irb>human.hello #=> "Hello murajun1978!"
irb>human.hi #=> "Hi murajun1978!"

みなさんも、新しいロジックがひょこっと出てきたら、新しいモデルを作成しましょう。

そのモデルをテストすることで品質も担保できますしね。

みなさんも、Railsでよきオブジェクト指向を満喫してください。