Edited at

Ruby Privateなインスタンスメソッド/クラスメソッドのテストを書く

@koshi_life です。

最近、Ruby関連のプロジェクトでテスト書いたり、リファクタしたりしています。そこでPrivate宣言したメソッドのテストの書き方を調べたので備忘です。


結論 Object#send を使う

Object#send メソッドを用いることで、Private宣言したメソッドをクラス外から呼び出しが可能です。

ちなみに、privateメソッドがコールできてしまうRubyの言語仕様/背景について以下エントリが参考になりました。

Ruby の private と protected 。歴史と使い分け


前提


  • Rails 5.2.3

  • Ruby 2.6.0

  • minitest 5.11.3


対象クラス


hoge.rb

class Hoge

# クラスメソッド
def self.pr_class_method(arg1, arg2)
"pr_class_method arg1=#{arg1} arg2=#{arg2}"
end

# クラスメソッド (キーワード引数)
def self.pr_class_method_kw(arg1:, arg2:)
"pr_class_method_kw arg1=#{arg1} arg2=#{arg2}"
end

# クラスメソッド (Block利用)
def self.pr_class_method_blk(arg1, &blk)
blk.call(arg1) if block_given?
"pr_class_method_blk arg1=#{arg1}"
end

private_class_method :pr_class_method,
:pr_class_method_kw,
:pr_class_method_blk

private

# インスタンスメソッド
def pr_instance_method(arg1, arg2)
"pr_instance_method arg1=#{arg1} arg2=#{arg2}"
end

end



send検証

$ rails c

# <インスタンスメソッド> 普通に呼ぶと NoMethodError エラー
> hoge = Hoge.new
> hoge.pr_instance_method(1,2)
# NoMethodError (private method `pr_instance_method' called for #<Hoge:0x00007ff7501ab338>)

# <インスタンスメソッド> sendで呼ぶ
> hoge.send(:pr_instance_method, 1, 2)
=> "pr_instance_method arg1=1 arg2=2"

# <クラスメソッド> 普通に呼ぶと NoMethodError エラー
> Hoge.pr_class_method(1, 2)
# NoMethodError (private method `pr_class_method' called for Hoge:Class)

# <クラスメソッド> sendで呼ぶ
> Hoge.send(:pr_class_method, 1, 2)
=> "pr_class_method arg1=1 arg2=2"

# <クラスメソッド> sendで呼ぶ (keyword引数)(blk引数)
> Hoge.send(:pr_class_method_kw, {arg1:'kw1', arg2:'kw2'})
=> "pr_class_method_kw arg1=kw1 arg2=kw2"

# <クラスメソッド> sendで呼ぶ (blk引数)
> Hoge.send(:pr_class_method_blk, 'blk-arg1') {|arg1| puts "it is block. arg1=#{arg1}"}
it is block. arg1=blk-arg1
=> "pr_class_method_blk arg1=blk-arg1"


テストコード


hoge_test.rb

require 'test_helper'

class HogeTest < ActiveSupport::TestCase
test 'Private Methodのテスト' do
# インスタンスメソッド
hoge = Hoge.new
actual1 = hoge.send(:pr_instance_method, 'i-A1', 'i-A2')
assert_equal('pr_instance_method arg1=i-A1 arg2=i-A2', actual1)

# クラスメソッド
actual2 = Hoge.send(:pr_class_method, 'c-A1', 'c-A2')
assert_equal('pr_class_method arg1=c-A1 arg2=c-A2', actual2)

# クラスメソッド (キーワード引数)
actual3 = Hoge.send(:pr_class_method_kw, { arg1: 'ckw-A1', arg2: 'ckw-A2' })
assert_equal('pr_class_method_kw arg1=ckw-A1 arg2=ckw-A2', actual3)
end
end



参考