rspec本一人読書会の続き。cucumberのお勉強メモです。
19.1 Step Definitions
定義されていないStepを含むfeatureを実行すると、cucumberはStep Definifionのひな形を出力してくれる。
19.2 World
全てのシナリオはWorldオブジェクトのインスタンスの文脈で実行される。Worldオブジェクトはデフォルトでは単なるObjectクラスのインスタンス。
Worldを使って、各step_definitionで使うヘルパーメソッドを定義するには下記のようWorldメソッドの引数にModuleを指定してあげる。
module MyHelper def some_helper # ... end end World(MyHelper)
どこで上記のような設定をしてもいいけど、 features/support/world.rb に書くのがおすすめらしい。
Worldの元となるクラスを別のものにすることも出来る。下記のようにWorldメソッドのブロックにインスタンスを入れてやると出来るみたい。
class MyWorld def some_helper #... end end World do MyWorld.new end
19.3 Calling steps within step definitions
stepをDRYにする方法のうちの一つは、高いレベルの抽象化をしたstepを作ること。そうするとたとえば下記のような書き方になるはず。
When /I transfer (.*) from (.*) to (.*)/ do |amount, source, target| When "I select #{source} as the source account" When "I select #{target} as the target account" When "I set #{amount} as the amount" When "I click transfer" end
でも下記のようにも書ける。
When /I transfer (.*) from (.*) to (.*)/ do |amount, source, target| steps %Q{ When I select #{source} as the source account And I select #{target} as the target account And I set #{amount} as the amount And I click transfer } end
どちらでも同じなので書きやすい方を選択するといい。
上記の二つの例は、step definitionsからstepを呼んでいる。これはDRY的にはいいけどstepがstep呼んでそこから別のstep呼んで・・・となるとデバッグしにくくなる。また、抽象性にばらつきのあるstep definitionsになりやすい。どうするかはバランスをみて決めたほうがいい。
19.4 Hooks
cucumberは下記の三つのメソッドでフックを実現している。
- Before
- scnenarioの前
- After
- scenarioの後
- AfterStep
- stepの後
hookはfeatures配下ならどこでも定義できるけどfeatures/support/hooks.rbに書くのがおすすめらしい。
また、hookは何回でも定義できる。例えばBeforeが10個あっても問題ない。
tagged hooks
特定のscenarioだけで実行させたいhookがあるときに使う。
Before("@foo") do puts "This will run before each scenario tagged with @foo" end
コマンドラインでの--tagsのようにするともっと複雑な条件を使える
Before("@foo,~@bar", "@zap") do puts "This will run before each scenario tagged with @foo or not @bar AND @zap" end
visibility
hookは便利だけど技術者以外にはよく分からないという欠点がある。技術者以外の人にわかるようにしたい場合はBackgroundを使う。
19.5 Background
Backgroundは与えられたfeature内の全てのシナリオの前に実行される。featureのなかで参照したいときにBefore hookの代わりとして使う。Feature内で共通したGivenをくくってBackgroundにだしてやると見通しが良くなりそう。
BeforeはBackgroundより前に実行される。
19.6 Multi-line Text
下記のようにすると複数行のテキストを引数にとれる。marginは最初の"で決まる。
Scenario: pending implementation Given a file named "example_without_block_spec.rb" with: """ describe "an example" do it "has not yet been implemented" end """ When I run "spec example_without_block_spec.rb" Then the exit code should be 0 And the stdout should include """ Pending: an example has not yet been implemented \(Not Yet Implemented\) .\/example_without_block_spec.rb:2 Finished in ([\d\.]*) seconds 1 example, 0 failures, 1 pending """ # ...
複数行のテキストは正規表現でキャプチャする必要はない。正規表現に含まれなかった文字列はブロックの最後の引数にはいる。
Given /a file named "([^\"]*)" with:/ do |filename, text| # ... end Then /the stdout should include/ do |text| # ... end
step中の文字は正規表現で評価されるので、複数行のテキスト中に()等の、正規表現で使われる特別な文字がある場合はがある場合はescapeをしておく必要がある
19.7 Tables in Steps
wikiスタイルのフォーマットでtableを表現できる。cucumberは行の最初に "|" を見つけたときにパースして、Cucumber::Ast::Tableオブジェクトにする。Cucumber::Ast::Tableオブジェクトは、hashの配列を返すhashesメソッドを持っている。
CucumberはCucumber::Ast::TableをStep definition中の最後のブロック引数として渡す。
Scenario Outlines
Scenariosキーワードで、Scenario Outlineに流し込むデータをテーブルで定義できる。
Scenario Outline: submit guess Given the secret code is "<code>" When I guess "<guess>" Then the mark should be "<mark>" Scenarios: all numbers correct | code | guess | mark | | 1234 | 1234 | ++++ | | 1234 | 1243 | ++-- | | 1234 | 1423 | +--- | | 1234 | 4321 | ---- |
ScenariosのエイリアスとしてExamplesキーワードもある。
複数行のテキストや、テーブルの値にもscenario outlineは使える。
Scenario Outline: Given a discount of <discount> When I order the following book: | title | price | | Healthy eating for programmers | <price> | Then the statement should read: """ Statement for David Total due: <total> """ Scenarios: | discount | price | total | | 10% | $29.99 | $26.99 | | 15% | $29.99 | $25.49 |
19.9 Configuration
cucumberのオプションをあらかじめ書いておくためのファイルとして cucumber.yml または config/cucumber.yml が定義されている。
例えば cucumber.yml に下記のように書いて
wip: --tags @wip features
下記のように実行すると
cucumber -p wip
下記のようにしたのと同じ結果になる
cucumber --tags @wip features
rails だと、自動的にdefaultと言う名前のprofileが探されるようなので
default: --format pretty
などとしておくと大変都合がいい。