メモ的な何か

技術的な私のメモになる予定です。

Rubyでテストコードの作成

はじめに

Rubyでテストコードのお試しをしました。
Rubyでのテスティングフレームワークは何種類かあります。
以下あたりが人気っぽいです。

今回はRSpecを選びました。
選ぶ基準はここを参考にさせていただきました。(情報量の多さとか使われている多さ等々)
今読んでいるパーフェクトRubyではRubyに同梱されているtest-unitの説明のみだったため、 RSpecで書いてみた内容をメモして置きます。

RSpec導入

Rubyでの導入は簡単です。
というか前回のCLIアプリケーションにも導入しています。
前回の記事の通り以下の初期実行にてテスティングフレームをRSpecを選択していれば -t オプションをつけたときに勝手に入ります。

bundle gem sample -b -t

もしここでRSpecを選んでなかったよって人は以下で導入できます。

bundle gem sample -b -t rspec

このコマンド後RSpecの設定ファイル(.rspecとspec/spec_helper.rb)も作成されてます。
途中からって人は多分.gemspecに書くとかすればいける気しますが、試してません。

またテストコードも一部自動で作成済みです。
spec/sample_spec.rbはlib/sample.rbに対するテストコードで、バージョンがnilでないこととfalseがtrueであることを確認しています。

RSpec.describe Sample do
  it "has a version number" do
    expect(Sample::VERSION).not_to be nil
  end

  it "does something useful" do
    expect(false).to eq(true)
  end
end

テストコードの実行

試しにこの状態ままで実行してみます。
実行のコマンドと実行結果は以下です。

$ bundle exec rspec

Sample
  has a version number
  does something useful (FAILED - 1)

Failures:

  1) Sample does something useful
     Failure/Error: expect(false).to eq(true)

       expected: true
            got: false

       (compared using ==)
     # ./spec/sample_spec.rb:7:in `block (2 levels) in <top (required)>'

Finished in 0.04696 seconds (files took 0.40854 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/sample_spec.rb:6 # Sample does something useful

もちろん後者は失敗しました。

テストの作成

続いてはテストを自分で作成してみます。
前回CLIアプリケーションのお試しで作ったSampleプロジェクトを使います。
Thor部分はテストし辛いので少しソースをいじります。
lib/sample/cli.rbを以下のように修正します。

  require "sample"
  require "thor"
 +require "sample/greeting"

  module Sample
    class Cli < Thor
        desc "hello {name}", "Hello {name}!"
        def hello(name)
 -          puts "Hello #{name}!"
 +          puts_str = Sample::Greeting.hello_create(name)
 +          puts puts_str
        end
    end
  end

lib/sample/greeting.rbを作成します。

require "sample"

module Sample
  class Greeting
    def self.hello_create(name)
      "Hello #{name}!"
    end
  end
end

見てわかるとおり挙動は変えてません。
テストするためだけにGreetingクラスを作成しました。

このGreetingクラスに対するテストコードを書きます。
rspec/sample/greeting_spec.rbを作成します。
このコードはhello_createメソッドの挙動を確認しています。最後だけわざと失敗するように作成しました。

require "sample/greeting"

RSpec.describe Sample::Greeting do
  it "return Hello Tanaka!" do
    expect(Sample::Greeting.hello_create("Tanaka")).to eq("Hello Tanaka!")
  end

  it "return Hello 田中!" do
    expect(Sample::Greeting.hello_create("田中")).to eq("Hello 田中!")
  end

  it "test failed" do
    expect(Sample::Greeting.hello_create("山田")).to eq("Hello 田中!")
  end
end

テストを実行してみます。
新たに作成したテストが追加で実行できていることが確認できると思います。

$ bundle exec rspec

Sample::Greeting
  return Hello Tanaka!
  return Hello 田中!
  test failed (FAILED - 1)

Sample
  has a version number
  does something useful (FAILED - 2)

Failures:

  1) Sample::Greeting test failed
     Failure/Error: expect(Sample::Greeting.hello_create("山田")).to eq("Hello 田中!")

       expected: "Hello 田中!"
            got: "Hello 山田!"

       (compared using ==)
     # ./spec/sample/greeting_spec.rb:12:in `block (2 levels) in <top (required)>'

  2) Sample does something useful
     Failure/Error: expect(false).to eq(true)

       expected: true
            got: false

       (compared using ==)
     # ./spec/sample_spec.rb:7:in `block (2 levels) in <top (required)>'

Finished in 0.05989 seconds (files took 0.43274 seconds to load)
5 examples, 2 failures

Failed examples:

rspec ./spec/sample/greeting_spec.rb:11 # Sample::Greeting test failed
rspec ./spec/sample_spec.rb:6 # Sample does something useful

今回のテストコードはものすごい基本的な文字列確認ですが、RSpecで提供されているメソッドをいろいろ使えば柔軟にテストを書くことができると思います。