LoginSignup
1
0

More than 3 years have passed since last update.

RiotとRRでテストケース書きたい

Last updated at Posted at 2020-04-14

はじめに

突然見たことも触ったこともないruby(フレームワークなし)を触らなければならなくなってしまい、
かつなかなかニッチなテストフレームワークを使ってテストが書いてあるので、お勉強しました。。。

しんどい。。。
そもそもrubyの文法まったく知らない。。。

riot

http://thumblemonks.github.io/riot/
https://github.com/thumblemonks/riot

(riotて暴動って意味ですよね・・・)
他のテストフレームワークより簡素に書けて早いのがウリなユニットテストフレームワークです。ですって

sample1.rb

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として参照できるようになっています

sample2.rb

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を通してアクセスします

sample3.rb

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 実際の値と期待値が等しいかどうか

Calc.rb
class Calc
  def add(num1, num2)
    num1 + num2
  end
end
test1.rb
context "add result" do
    setup { 
     c = Calc.new
     c.add(5, 8)
    }
    # pass
    asserts{ topic }.equals{ 13 }
  end

◆asserts.equivalent_to 実際の値と期待値が同等かどうか
※微妙なテストケースです

User.rb

class User
    def initialize(name, age)
        @name = name
        @age = age
    end

    def do_something(str)
        action = str == "nothing" ? nil : str
    end
end
test2.rb
context "same objects?" do
    u = u2 = User.new("taro", 15)

    # pass
    asserts{ u }.equivalent_to(u2)
    end

◆asserts.nil 実際の値がnilかどうか ※期待値は不要
※テスト対象が上記Userクラス(do_something)なため省略

test3.rb
context "whats you do" do
    setup{
      u = User.new("taro", 15)
      u.do_something("nothing")
    }
    # pass
    asserts{ topic }.nil
  end

◆asserts.raises テストで予想される例外が発生しているか
※{}内で期待される例外が発生しているか

User.rb
class User

  # 意図的に例外を発生させる
  def raises_exception
        raise ArgumentError 
  end
test4.rb
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 予想される型で結果が返ってきているか

User.rb

def return_arr(str1)
        array = []
        array.append(str1)
end
test5.rb
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

Use.rb
class User
  def do_something(str)
    action = str == "nothing" ? nil : str
    end
test6.rb

context "respond_to?" do

    # 生成したインスタンスにdo_somethingというメソッドがあるか
    # pass
    asserts{User.new("koji", 36)}.respond_to{:do_something}
end

◆asserts.size テスト結果のサイズが期待通りか

User.rb

class User
  def return_arr(str1)
        array = []
        array.append(str1)
  end
test7.rb

context "arrar size correct?" do
    setup{
      u = User.new("hiromu", 17)
      u.return_arr("hello")
    }

    # pass
    asserts{ topic }.size(1)
  end

◆asserts.empty テストの結果が空かどうか

User.rb

class User
  def return_something(str)
        re = str == "nothing" ? [] : str
  end
end
test8.rb

context "return empty?" do
    setup{
      u = User.new("taro", 20)
      u.return_something("nothing")
    } 

    # pass
    asserts{ topic }.empty   
  end

・hookup
テスト対象のtopicを変更することなく、topicを変更したい(例えば、インスタンス変数に新しい値を追加したい)ときに使います
hookupを使用すれば、↓と同様のことができます

sample4.rb

setup do
  topic.do_something
  topic
end
sample5.rb

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
ダブルルビーと言うらしいです。
テストダブル(モックとかスタブとか作る)のフレームワーク、みたいです。

・スタブ

stub1.rb

stub(スタブにしたいobject).スタブにしたいmethod_name {返したいreturn_value_}

スタブにしたいメソッドに引数を与えることもでき、与えられた引数以外が来た場合は動作しないようになっています。

stub2.rb

stub(スタブにしたいobject).スタブにしたいmethod_name( 引数 ) { 返したいreturn_value }

メソッド内で生成されるインスタンスをスタブにしたいときはこんな感じで作れます。

stub3.rb

any_instance_of(newするクラス) do |x|
        stub(x).スタブにしたい関数 { 返したい値 }
      end

・モック
モックはスタブと異なり、作成したモックがテストで呼ばれないとエラーになります。

mock1.rb

mock(モックにしたいobject).モックにしたいmethod_name {返したいreturn_value_}
mock2.rb

mock(モックにしたいobject).モックにしたいmethod_name( 引数 ) { 返したいreturn_value }

おわりに

実際にコード書ければよかったんですが、環境構築に時間がかかりそうだったのでいったんここで。。。

絶対書きます。。。

20200415追記:
riotを使用した簡易なソースを書きました。
次はrrを使ってモック・スタブを作りながら簡易なソースを書きます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0