「privateメソッドのテストについての考え方」を読んで #yochiyochirb

highwide.hatenablog.com

を読んで、「自分なら設計を変えて、publicにしてからテストを書くなー」と思ったので、考え方・直し方の一例としてブログを書く。

元の設計

元記事のスライドの途中に出てくるコードはこんな感じで、バッチ処理などでよくある設計。

module Tasks
  module Hoge
    class Sender
      def self.execute
        data = aggregate_data
        processed_data = process_data(data)
        send_s3(processed_data)
      end
    end
  end
end

コードの臭い

個人的なリファクタリング原則で「引数が1つのメソッドは、その引数のインスタンスメソッドに書き換えられる」がある。*1

あと、元コードだと「データ収集、加工、s3に置く」のが1メソッドになっていてテストし辛いので、そこも分ける。

module Tasks
  module Hoge
    class Sender
      def self.execute
        instance.process_data.send_s3
      end

      def self.instance
        data = aggregate_data
        new(data)
      end

      def self.aggregate_data
        # データを集める処理
      end

      def initialize(data)
        @data = data
      end
      attr_reader :data

      def process_data
        processed = data.group_by(&:first)
          .sort
          .map { |key, value| [values[0], values[1]] }

        # Immutableの方がメンテしやすいので、新しいインスタンスを返す設計にしてある
        Sender.new(processed)
      end

      def send_s3
        # s3に置く処理
      end
    end
  end
end

この構造にすると、データ収集・加工・s3アップロードをそれぞれテストしやすくなる。

まとめ

単にpublicに変えるわけじゃなくて、設計を見直した結果publicになるものかなと思ってます。

*1:個人的によく使う原則なんだけど、何か名前あったりするのかな