MinitestとRubyの変数アクセスバリデーション
minitestを試しに使っていたら、C#を触っていた時のオブジェクト内の変数(field)へのアクセス制限(プロパティ)やメソッドへのアクセス制限(public, private, protected)をRubyではどのように表現しているのか気になったのでメモを残しておく。
minitestの基本的な使い方。
minitestのテスト名はスネークケースで書かないとテストとして認められないらしい。(いつも通りキャメルケースで書いたら認識されなかった。)テストコードはこんな感じ。
require 'minitest/autorun' require './User.rb' #テストするファイルを相対パスで指定。 require "minitest/reporters" #テスト結果をリッチに表示させるツール。gem install minitest-reportersが必要。 Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new] class UserTest < Minitest::Test #この継承関係にしておくことでテストとして機能させることができる。このクラスのインスタンス化は不要。 def setup @hiroki = User.new('Hiroki', 70) @takumi = User.new('Takumi', 72) end def test_hiroki_heavier_than_takumi? assert_equal @hiroki.heavierThan?(@takumi), false end def test_takumi_heavier_than_hiroki? assert_equal @takumi.heavierThan?(@hiroki), true end end
こんな感じでテストが書ける。この辺はNUnitとかと特に変わりない。
この時のテスト対象のコードが
class User attr_reader :name def initialize(name, weight) @name = name @weight = weight end def heavierThan?(otherUser) return otherUser.weight < @weight end protected def weight return @weight end end
こんな感じだった。
まず気になったのがattr_readerで、これがオブジェクトのフィールドに対するプロパティの役割をするらしい。C#では
public int Hp { get => _hp; set { if (_hp > 0) { _hp = value; } } }
こんな風にgetとsetどちらが使用可能なのか、いちいち定義するが、Rubyでは
- attr_readerなら読み込み可能
- attr_writerなら書き込みが可能
- attr_accessorなら読み書き可能
、となっている。実際、先ほどのUser classのnameプロパティを読み込み可能から読み書き可能に変更してみると、
require './User.rb' @hiroki = User.new('Hiroki', 70) puts @hiroki.name @hiroki.name = "Haruya" puts @hiroki.name
とすると、
Hiroki Haruya
と出力することが出来る。ただ、この方法だと、C#でやってたみたいに、条件付きアクセサ(値が0以上なら書き込み可能にする)みたいなことはできなくなる。
つぎに、User classのprotectedメソッド。C#ではそのクラスの子クラスのインスタンスからはアクセスできるフィールドになっていた。
ところが、User classに子クラスを作ってそこからアクセスしようとしたけど出来なかった。
いろいろ調べたところ、Rubyではprivateもprotectedもオブジェクト自身からしかアクセスできないメソッドだった。唯一の違いはPrivateでは関数形式での呼び出しができない、という点だった。
def weightPublic return @weight end protected def weightProtected return @weight end private def weightPrivate return @weight end def accessToItSelf puts "access to Public method: #{weightPublic}"#アクセス可能 puts "access to Public method: #{self.weightPublic}"#アクセス可能 puts "access to Protected method: #{weightProtected}"#アクセス可能 puts "access to Protected method: #{self.weightProtected}"#アクセス可能 puts "access to Private method: #{weightPrivate}"#アクセス可能 puts "access to Private method: #{self.weightPrivate}"#アクセス不可能。 end
C#ではオブジェクト自身のメソッドにアクセスする場合、selfを使っても、使わなくてもよかった。selfを使わずにアクセスしたいメソッド名だけでメソッドにアクセスすることを「関数形式の呼び出し」という。Rubyでは基本的にこれを許さないのだが、Public, Protectedなメソッドに対しては、これができるようになっている。
(3つあるうちの2つ許していたらあんまり関数形式の呼び出しを禁止していることになっていないと思うのだけど。。。)