Tbpgr Blog

元エンジニア 人事 tbpgr(てぃーびー) のブログ

Ruby | Windows7環境 + コマンドライン + ワイルドカード展開の罠をきっかけにRSpecのコードリーディングをした話

概要

Windows7環境 + コマンドライン + ワイルドカード展開の罠をきっかけにRSpecのコードリーディングをした話

経緯

※タイトルでピンとくる方は「何を今更・・」という情報だと思います。

RSpecの基本的な利用法を覚えるためにrspecコマンドの各オプションを一つずつ実行していました。
rspec --pattern(または-P)を試そうとして以下のような構成でテストコードを作りました。
本来はプロダクトコードが必要ですが、rspecのpatternオプションの検証には不要なので
specのみを作成しました。

構成

$ tree
┗ spec
    ┣ helper.rb
    ┣ it
    | ┣ scenario1_spec.rb
    | ┣ scenario2_spec.rb
    | ┗ scenario3_spec.rb
    ┣ spec_helper.rb
    ┗ ut
        ┣ hage_spec.rb
        ┣ hige_spec.rb
        ┗ hoge_spec.rb

全体を実行

$ rspec -fs
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}

Scenario1
  scenario1_1
  scenario1_2

Scenario2
  scenario2_1
  scenario2_2

Scenario3
  scenario3_1
  scenario3_2

Hage
  hage1 1
  hage1 2
  hage2

Hige
  hige1 1
  hige1 2
  hige2

Hoge
  hoge1 1
  hoge1 2
  hoge2

Finished in 0.00387 seconds
15 examples, 0 failures

単体テスト(ut)のみを実行

まずUbuntu環境。
※オプションの指定は「-P」「--pattern」のどちらでもよい。

$ rspec -fs -P "spec/ut/*.rb"
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}

Hage
  hage1 1
  hage1 2
  hage2

Hige
  hige1 1
  hige1 2
  hige2

Hoge
  hoge1 1
  hoge1 2
  hoge2

Finished in 0.00217 seconds
9 examples, 0 failures

想定通り動きました。
しかし、Windows7環境では下記のようになりました。

$ rspec -fs -P "spec/ut/*_spec.rb"
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}

Hige
  hige1 1
  hige1 2
  hige2

Hoge
  hoge1 1
  hoge1 2
  hoge2

Finished in 0.001 seconds
6 examples, 0 failures

Hageクラス関連のspecが動いて居ません。

runner.rbをデバッグして内容を確認

rspec_coreのrunner.rbのRSpec::Core::Runner.self.autorunの処理開始直後でARGVの中身を確認。

Ubuntu環境

["-fs", "-P", "spec/ut/*_spec.rb"]

Windows環境

["-fs",
 "-P",
 "spec/ut/hage_spec.rb",
 "spec/ut/hige_spec.rb",
 "spec/ut/hoge_spec.rb"]

Windows環境はワイルドカードが展開されてしまいました。
それらしき情報がないかググったらRuby公式に載っていました。

http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2frubycmd.html

Windows環境はそういう仕様なんですね。

ということで下記のようにシングルクォートで指定したらWindows環境でも正しく動作しました。

rspec -fs -P 'spec/ut/*_spec.rb'

ただcmdを利用した場合は上記で良いのですが、cygwinのコンソール(cyglaunch含む)から実行すると
上記でもダブルクォートと同様の動きになります。
仕方がないので以下のように指定したところ、cyglaunchでも正しく動作しました。

rspec -fs -P"spec/ut/*_spec.rb"

RSpecのコードリーディング

ここまでrspec_coreのrunner.rbにしか触れていませんが
実際はもっと別の場所からデバッグしていたので色々ソースをみて解決に時間がかかったしまいました。
おかげでRSpecのコードを読むきっかけになりましたが。

主に見たのは下記のコード
https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/configuration.rb
https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/configuration_options.rb
https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/runner.rb

railsのactive_support/core_extのコードを色々と読んでいた経緯もあって対比が面白かった。
共通点はメソッドの処理が短いこと。例外的に長い部分はありますが大抵のメソッドが1行〜5行程度。

RSpecはBDDフレームワークなだけあって、人に優しい命名にこだわっていますね。
Railsと異なる部分ですが、時々とても説明的で長い変数名・メソッド名がでてきました。
1行の処理でも積極的にメソッド化していました。

・処理粒度を合わせるComposed Methodとして
・命名で処理内容を把握させるための「説明メソッド」として
・privateメソッドはコメントを付与しない代わりに特に詳しいメソッド名で読ませる

などの意味合いがあるのだろうと思いました。

※長いメソッド名の代表例2つ

def underscore_with_fix_for_non_standard_rspec_naming(string)
def assert_no_example_groups_defined(config_option)

個人的に読みやすく好みのコードでした。