- Cucumber: http://cukes.info/
- Gherkin: https://github.com/cucumber/gherkin
お題
Cucumberは、featureファイルに記述されたシナリオステップに対応する「ステップ定義(=実装)」をどうやって見つけてるのだろうか?というのが事の発端。
Cucumberのコードを読みつつ、指定したシナリオステップにマッピングされた「ステップ定義」を検索するRubyコードを書いてみる。
コードを読む
Cucumber::Runtime::SupportCode クラスがマッチングのコア実装と思われる。ここを中心にざっと見てみる。
処理の流れとしては、
Rubyコード
Cucumber::Runtimeクラスにstep_match(step_name, name_to_report=nil)の定義があるので、これを叩けるように前提を揃えてやればよさそう。
- Configurationの指定
- 「ステップ定義」ファイルの読み込み
1.はコマンドライン引数からオプション指定で構築できるようにする。
2.は、private methodなので外部から実行できるようにする。
Rubyコードはこちら。featuresはexamplesを使用。
$ ruby find_step_definition.rb "the result should be 1.5 on the screen" examples/i18n/en/features/
step definition
file: examples/i18n/en/features/step_definitons/calculator_steps.rb
line: 22
step: {"source"=>"the result should be (.*) on the screen", "flags"=>""}
arguments:
{"offset"=>21, "val"=>"1.5"}
jaも検索してみる。
$ ruby find_step_definition.rb "1.5 を表示" examples/i18n/ja/features/
step definition
file: examples/i18n/ja/features/step_definitons/calculator_steps.rb
line: 7
step: {"source"=>"(.*) を表示", "flags"=>""}
arguments:
{"offset"=>0, "val"=>"1.5"}
なかなかいい感じ。
ファイル名と行番号だけでなく、RDocやYARDみたくソースコードも表示できれば尚好し、かな。
yard-cucumberなんてのがあってYARD::CodeObjects::Baseを継承してがんばればやれそうな感触あったけど、ひとまずやりたいことはできたので終了。
Appendix
Cucumber::Runtimeクラスに「ステップ定義」一覧をJSONファイルにダンプするメソッドが定義されていたのでついでに使ってみた。
Rubyコードはこちら。
$ ruby dump_step_definitions.rb --dotcucumber /path/to/.cucumber/ examples/i18n/en/features
write to /path/to/.cucumber/stepdefs.json
生成されたJSONファイル。
[
{
"source": "I have entered (\\d+) into the calculator",
"flags": "",
"file_colon_line": "examples/i18n/en/features/step_definitons/calculator_steps.rb:14",
"steps": [
{
"name": "I have entered 2 into the calculator",
"args": [
{
"offset": 15,
"val": "2"
}
]
},
{
"name": "I have entered 3 into the calculator",
"args": [
{
"offset": 15,
"val": "3"
}
]
}
]
},
{
"source": "I press (\\w+)",
"flags": "",
"file_colon_line": "examples/i18n/en/features/step_definitons/calculator_steps.rb:18",
"steps": [
{
"name": "I press divide",
"args": [
{
"offset": 8,
"val": "divide"
}
]
}
]
},
{
"source": "the result should be (.*) on the screen",
"flags": "",
"file_colon_line": "examples/i18n/en/features/step_definitons/calculator_steps.rb:22",
"steps": [
{
"name": "the result should be 1.5 on the screen",
"args": [
{
"offset": 21,
"val": "1.5"
}
]
},
{
"name": "the result should be <output> on the screen",
"args": [
{
"offset": 21,
"val": "<output>"
}
]
}
]
}
]