Hamamatsu.rb#64 のrspecに関する補足事項

2016-05-12
Ruby RSpec

Hamamatsu.rb(浜松Ruby) #64 に参加しました

今回は RSpec の回だったのですが

RSpecの環境構築をしている際に、

`bundle gem [gemname]` とすると簡単に環境整いますよ

と口に挟んでしまい混乱させてしまいました

こちらのコマンドで RSpec の 環境構築をすることについて補足しておきたいと思います

環境等

$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
$ bundle -v
Bundler version 1.12.3
$ cat ~/.bundle/config
---
BUNDLE_GEM__COC: false
BUNDLE_GEM__MIT: false
BUNDLE_GEM__TEST: rspec

bundle gem コマンドとは?

RubyGems を作るためのコマンドです

Ruby のライブラリの配布形式です

説明は省略しますが、作ったライブラリは bin/rake release コマンドで RubyGemsサーバーに登録することができます

bundle gem を利用したRSpec環境の構築

以下のコマンドで rspec_example という gem を作成します

$ bundle gem rspec_example

以下のようなディレクトリ構造になります

rspec_example
├── Gemfile
├── README.md
├── Rakefile
├── bin
│   ├── console
│   └── setup
├── lib
│   ├── rspec_example
│   │   └── version.rb
│   └── rspec_example.rb
├── rspec_example.gemspec
└── spec
    ├── rspec_example_spec.rb
    └── spec_helper.rb

rspec_example.gemspec の編集

bundle gem で作成した場合 (オプションを指定しない場合) デフォルトで rspec がインストールされるように設定されています

通常ですと bundle install コマンドでそれらのライブラリをインストールできます

しかし、bundle gem コマンド実行直後に bundle install コマンドを実行すると以下のようになります

$ bundle install --binstubs
You have one or more invalid gemspecs that need to be fixed.
The gemspec at /Users/kengos/workspace/sandbox/rspec_example/rspec_example.gemspec is not valid.
Please fix this gemspec.
The validation error was '"FIXME" or "TODO" is not a description'

TODO や FIXME が含まれているとエラーがでてしまうようです

rspec_example.gemspec というファイル を開き以下のように変更します

-  spec.summary       = %q{TODO: Write a short summary, because Rubygems requires one.}
+  spec.summary       = %q{Write a short summary, because Rubygems requires one.}
-  spec.description   = %q{TODO: Write a longer description or delete this line.}
+  spec.description   = %q{Write a longer description or delete this line.}
-  spec.homepage      = "TODO: Put your gem's website or public repo URL here."
+  spec.homepage      = ""

再度 bundle install を実行すると今度は実行できるはずです

$ bundle install --binstubs
Fetching gem metadata from https://rubygems.org/
Fetching version metadata from https://rubygems.org/
Resolving dependencies...
Using rake 10.5.0
Using bundler 1.12.3
Using diff-lcs 1.2.5
Using rspec-support 3.4.1
Using rspec_example 0.1.0 from source at `.`
Using rspec-core 3.4.4
Using rspec-expectations 3.4.0
Using rspec-mocks 3.4.1
Using rspec 3.4.0
Bundle complete! 4 Gemfile dependencies, 9 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

※実際に 公開用のRubyGemを作成する場合は きちんと TODO の箇所を設定する必要があります

RSpecの実行

上記では bundle install --binstubs コマンドでインストールをしました

このコマンドでインストールすると bin 以下に様々なファイルが作成されます

rspec_example/bin
├── bundler
├── console
├── htmldiff
├── ldiff
├── rake
├── rspec
└── setup

bin/rspec が含まれていますので、実行してみます

$ bin/rspec

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

Failures:

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

       expected: true
            got: false

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

Finished in 0.01884 seconds (files took 0.12111 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/rspec_example_spec.rb:8 # RspecExample does something useful

上記のようになれば RSpec の実行環境が整ったことになります

specファイルの修正

インストール直後にサンプルの specファイルが含まれています

このspecは落ちるように記述されています

spec/rspec_example_spec.rb このファイルを修正します

require 'spec_helper'

describe RspecExample do
  it 'has a version number' do
    expect(RspecExample::VERSION).not_to be nil
  end

  it 'does something useful' do
-    expect(false).to eq(true)
+    expect(false).to eq(false)
  end
end

再度 bin/rspec を実行します

$ bin/rspec

RspecExample
  has a version number
  does something useful

Finished in 0.00144 seconds (files took 0.08446 seconds to load)
2 examples, 0 failures

今度は spec が failure にならずに 正しく pass しています

簡単な機能を持ったクラスを作ってみる

テスト対象となる簡単なクラスファイルの作成

lib/rspec_example 以下に my_class.rb というファイルを作成します

module RspecExample
  class MyClass
    def sum(*args)
      0
    end
  end
end

こちらのファイルがロードされるように

lib/rspec_example.rb から require するようにします

require "rspec_example/version"
+ require "rspec_example/my_class"

module RspecExample
  # Your code goes here...
end

specファイルの作成

specファイルには命名規則があり テスト対象の ファイル名 + _spec.rb とします

この場合 テスト対象が my_class.rb というファイルですので

spec 以下に my_class_spec.rb というファイルを作成します

require 'spec_helper'

RSpec.describe RspecExample::MyClass do
  describe '#sum' do
    subject { described_class.new.sum(1, 2, 3, 4, 5) }
    it { is_expected.to eq 15 }
  end
end

described_class.newRspecExample::MyClass.new を意味します

spec の実行

以下のような実行結果になれば問題ありません

MyClass#sum のメソッドは 合計を返すように実装されておらず 常に 0 を返すようになっているため、このspecは落ちます

今回は 独自のクラスファイルの追加方法を示したかったので、 このspecがきちんとpassするような実装については省略します

MyClass#sum をきちんと実装して この spec が落ちないように修正してみてください

$ bin/rspec

RspecExample::MyClass
  #sum
    should eq 15 (FAILED - 1)

RspecExample
  has a version number
  does something useful

Failures:

  1) RspecExample::MyClass#sum should eq 15
     Failure/Error: it { is_expected.to eq 15 }

       expected: 15
            got: 0

       (compared using ==)
     # ./spec/my_class_spec.rb:6:in `block (3 levels) in <top (required)>'

Finished in 0.02232 seconds (files took 0.1487 seconds to load)
3 examples, 1 failure

Failed examples:

rspec ./spec/my_class_spec.rb:6 # RspecExample::MyClass#sum should eq 15