はじめに
突然見たことも触ったこともないruby(フレームワークなし)を触らなければならなくなってしまい、
かつなかなかニッチなテストフレームワークを使ってテストが書いてあるので、お勉強しました。。。
しんどい。。。
そもそもrubyの文法まったく知らない。。。
riot
・http://thumblemonks.github.io/riot/
・https://github.com/thumblemonks/riot
(riotて暴動って意味ですよね・・・)
他のテストフレームワークより簡素に書けて早いのがウリなユニットテストフレームワークです。ですって
context "An empty Array" do
setup { Array.new }
asserts("it is empty") { topic.empty? }
end # An Array
・context
どんなテストをするのかの説明を書きます
・setup
何をテスト対象とするのかを決めます
上記の場合だと{Array.new}で生成されたArrayがテスト対象になります
※複数定義することもできます
複数定義した場合は上から評価され、次のsetupのtopic(↓参照)になります
2行目のsetupで生成したcheeseは3行目のsetupでtopicとして参照できるようになっています
context "A cheesey order" do
setup { Cheese.create!(:name => "Blue") }
setup { Order.create!(:cheese => topic, :purchase_order => "123-abc") }
asserts_topic.kind_of(Order) # I love tests that are readable
end
・topic
setupで定義されたものをtopicと言います
今回の例だと、生成したArrayにアクセスしたい際はtopicを通してアクセスします
context "A string" do
setup { "foo" }
setup { topic * 2 }
asserts(:length).equals(6)
end
複数setupを定義した際、3行目のsetup(topic * 2 (= "foofoo"))では、topicを通して2行目のsetupで定義したtopic("foo")にアクセスしています
・asserts
アサーションしたい時には組み込みのAssertionMacroクラスを使用してアサーションします。
よく使いそうなものを抜粋してちょろっとコードを:
◆asserts.equals 実際の値と期待値が等しいかどうか
class Calc
def add(num1, num2)
num1 + num2
end
end
context "add result" do
setup {
c = Calc.new
c.add(5, 8)
}
# pass
asserts{ topic }.equals{ 13 }
end
◆asserts.equivalent_to 実際の値と期待値が同等かどうか
※微妙なテストケースです
class User
def initialize(name, age)
@name = name
@age = age
end
def do_something(str)
action = str == "nothing" ? nil : str
end
end
context "same objects?" do
u = u2 = User.new("taro", 15)
# pass
asserts{ u }.equivalent_to(u2)
end
◆asserts.nil 実際の値がnilかどうか ※期待値は不要
※テスト対象が上記Userクラス(do_something)なため省略
context "whats you do" do
setup{
u = User.new("taro", 15)
u.do_something("nothing")
}
# pass
asserts{ topic }.nil
end
◆asserts.raises テストで予想される例外が発生しているか
※{}内で期待される例外が発生しているか
class User
# 意図的に例外を発生させる
def raises_exception
raise ArgumentError
end
context "raises Argument Exception?" do
setup{u = User.new("kono taro", 55)}
# assertsブロックに例外が発生する処理を書く
# fail
asserts{ u.raises_exception }.raises{ NameError }
# pass
asserts{ u.raises_exception }.raises{ ArgumentError }
end
◆asserts.kind_of 予想される型で結果が返ってきているか
def return_arr(str1)
array = []
array.append(str1)
end
context "return type is Array?" do
setup{
u = User.new("hanako", 12)
u.return_arr("hi")
}
# pass
asserts{ topic }.kind_of{ Array }
end
◆assert.respond_to テストの結果が、指定されたメソッドに応答するオブジェクトかどうか
※Object#respond_to?のような感じです
https://docs.ruby-lang.org/ja/latest/method/Object/i/respond_to=3f.html
class User
def do_something(str)
action = str == "nothing" ? nil : str
end
context "respond_to?" do
# 生成したインスタンスにdo_somethingというメソッドがあるか
# pass
asserts{User.new("koji", 36)}.respond_to{:do_something}
end
◆asserts.size テスト結果のサイズが期待通りか
class User
def return_arr(str1)
array = []
array.append(str1)
end
context "arrar size correct?" do
setup{
u = User.new("hiromu", 17)
u.return_arr("hello")
}
# pass
asserts{ topic }.size(1)
end
◆asserts.empty テストの結果が空かどうか
class User
def return_something(str)
re = str == "nothing" ? [] : str
end
end
context "return empty?" do
setup{
u = User.new("taro", 20)
u.return_something("nothing")
}
# pass
asserts{ topic }.empty
end
・hookup
テスト対象のtopicを変更することなく、topicを変更したい(例えば、インスタンス変数に新しい値を追加したい)ときに使います
hookupを使用すれば、↓と同様のことができます
setup do
topic.do_something
topic
end
context "A Person" do
setup { Person.new(:name => "Master Blasterr") }
denies(:valid?) # :(
context "with valid email" do
# ここをsetupにしてしまうと、topicがpersonではなく、person.emailになってしまう
# テスト対象はpersonなので、topicがpersonに向く必要がある
# hookupを使用するとsetupと同様のことを行うが、返すtopic(person)は変わらない
hookup { topic.email = "master@blast.err" }
asserts(:valid?) # Yay!
end # with valid email
end # A complex thing
RR
https://www.rubydoc.info/gems/rr
ダブルルビーと言うらしいです。
テストダブル(モックとかスタブとか作る)のフレームワーク、みたいです。
・スタブ
stub(スタブにしたいobject).スタブにしたいmethod_name {返したいreturn_value_}
スタブにしたいメソッドに引数を与えることもでき、与えられた引数以外が来た場合は動作しないようになっています。
stub(スタブにしたいobject).スタブにしたいmethod_name( 引数 ) { 返したいreturn_value }
メソッド内で生成されるインスタンスをスタブにしたいときはこんな感じで作れます。
any_instance_of(newするクラス) do |x|
stub(x).スタブにしたい関数 { 返したい値 }
end
・モック
モックはスタブと異なり、作成したモックがテストで呼ばれないとエラーになります。
mock(モックにしたいobject).モックにしたいmethod_name {返したいreturn_value_}
mock(モックにしたいobject).モックにしたいmethod_name( 引数 ) { 返したいreturn_value }
おわりに
実際にコード書ければよかったんですが、環境構築に時間がかかりそうだったのでいったんここで。。。
絶対書きます。。。
20200415追記:
riotを使用した簡易なソースを書きました。
次はrrを使ってモック・スタブを作りながら簡易なソースを書きます。