Gaugeのスクリプトを詳しく見てみる
前回の記事でGaugeを触ってみました。
今回は前回の記事の中で動かした実際のスクリプトを詳しく見てみましょう。
Specificationを見る
.spec
で定義されているものをGaugeではSpecificationと呼びます。名前のとおりですが、ここにはその機能の仕様を記載します。場合によってはユーザーストーリーでも構わないと思います。これがGaugeの世界での1つのテスト実行単位になります。
それではexample.spec
を例に中身を見ていきましょう。
# Specification Heading This is an executable specification file. This file follows markdown syntax. Every heading in this file denotes a scenario. Every bulleted point denotes a step. To execute this specification, run gauge run specs * Vowels in English language are "aeiou". ## Vowel counts in single word tags: single word * The word "gauge" has "3" vowels. ## Vowel counts in multiple word This is the second scenario in this specification Here's a step that takes a table * Almost all words have vowels |Word |Vowel Count| |------|-----------| |Gauge |3 | |Mingle|2 | |Snap |1 | |GoCD |1 | |Rhythm|0 |
1行目は
#
から始まります。markdown syntaxのh1にあたる#
で始まるこの行は、この仕様のタイトルを表記する場所です。続く3行はこのSpecificationの説明を記載するところ。というより、Gaugeの予約語?を含まない部分はただの文字列として扱われ、その文がそのままテストのレポートに出力されることになるようです。
続いて
*
で始まる* Vowels in English language are "aeiou".
。Gaugeの中で*
から始まる文はStepとして扱われます。ただし、今回のように後述予定のScenarioの前にStepを記載した場合、このStepはContext Stepとして扱われます。Context StepはそれぞれのScenarioが実行される前に必ず実行される処理になり、テストのためのPre-conditionを設定することなどが可能になります。Stepの中に記載されている
"aeiou"
は外部パラメータとして扱われ、Stepの実装とのなる関数への引数となります。Stepの実装については後ほど説明したいと思います。markdown syntax h2に相当する
##
で始まるこの行は、先程も登場したScenarioと呼ばれるものになります。私の理解ではGaugeの世界では1つのScenarioが一般的な1つのテストケースに相当すると思われます。1つのSpecificationは必ず1つ以上のScenarioを含む必要があるようです。tags
はSpecificationの配下、もしくはScenario配下に定義可能です。定義されたtags
はテスト実行時のフィルターとして利用可能で、特定のタグを持ったSpecification or Scenarioのみを実行するなどの使い方ができます。*
から始まるこの行は上述の通りStepとなります。Scenarioの中に記載されているので、このStepはContext stepではなく、通常のStep、つまりテストケースの1つのステップとして扱われます。## Vowel counts in multiple word
は2つ目のScenario(テストケース)で、続く2つの行はこのテストに関する補足の説明です。*
で始まるこの行は上記に記載した通りテストのステップになります。ただし今回はその直後にテーブルが続いています。このテーブルはTable Parametersとして扱われ、直前のStepの実装となる関数の引数として扱われ、表の各行毎にそのStepが評価されます。今回の例ではWord
の中に母音(vowel)が何個あるかカウントし、Vowel Count
と一致するか確認することになるので、Gauge
では母音が3
個、Mingle
では母音が2
個、といった具合です。同じような処理を変数を変えて実施したいときに便利に使えそうです。
以上でSpecificationの説明が終わりました。続いてStepの実装について見ていきましょう。
step_impl.py を見る
step_impl.py
には実際のテストの処理を行う実装がなどが記載されています。
from getgauge.python import step, before_scenario, Messages vowels = ["a", "e", "i", "o", "u"] def number_of_vowels(word): return len([elem for elem in list(word) if elem in vowels]) # -------------------------- # Gauge step implementations # -------------------------- @step("The word <word> has <number> vowels.") def assert_no_of_vowels_in(word, number): assert str(number) == str(number_of_vowels(word)) @step("Vowels in English language are <vowels>.") def assert_default_vowels(given_vowels): Messages.write_message("Given vowels are {0}".format(given_vowels)) assert given_vowels == "".join(vowels) @step("Almost all words have vowels <table>") def assert_words_vowel_count(table): actual = [str(number_of_vowels(word)) for word in table.get_column_values_with_name("Word")] expected = [str(count) for count in table.get_column_values_with_name("Vowel Count")] assert expected == actual # --------------- # Execution Hooks # --------------- @before_scenario() def before_scenario_hook(): assert "".join(vowels) == "aeiou"
まずは
import
。gauge pythonではお決まりになりますが、必要なモジュールをインポートします。getgauge.python
はpythonで必要なgaugeのモジュールがすべて入っています。今回はstep
,before_scenario
,Messages
を使います。次に登場する変数
vowels
と関数number_of_vowels
は今回の例ではテストの対象となる部分になります。今回のテストの対象となるnumber_of_vowels
は引数をなるword
の中に何個の母音が含まれているかをカウントする関数になるようです。続いて実際のテスト部分の実装になります。
@step
から続くアノテーション文。ダブルクオートで囲まれている中身を見てもわかりますが、これがSpecificationの中で呼び出していたStepの実装になります。また<>
囲われた部分はSpecificationから外部パラメータを与えるための仮引数になります。ここで定義された仮引数が次に続く関数の仮引数にそのまま使われます。直後の
assert_no_of_vowels_in
は直前の@step
で定義されたStepの実装部分です。Specificationからは@step
に記載された文字列で呼び出しますが、実際に処理として行われるのは実装部分であるこちらです。この関数では<word>
と<number>
を与え、テストの対象number_of_vowels
がその<word>
で期待した数<number>
の母音を返すかをassert
を使って確認しています。次の
@step
とその実装部分では<vowels>
とgiven_vowels
がそれぞれ仮引数として定義されています。名前が違うので別物と勘違いしそうですが、同じものです。@step
内と実際の関数の仮引数の名前は一致している必要はなく、順序で参照が決まります。また同実装の中に
Messages.write_message
という処理を呼び出しています。この処理の中で記載された文字列は、テスト実行後に出力されるテストレポートに記載されます。Specificationでも#
や*
を使わずに文字列を埋め込むことで、同様のことができましたが、こちらのやり方はでは仮引数などを用いて外部パラメータも埋め込むことができるようでうす。Custom Messagesと呼ばれる機能のようです。最後の
@step
では<table>
を用いています。Specificationでも登場したテーブルですが、ここで引数として用いられます。table
から値を取り出す場合はtable.get_column_values_with_name
を使って値を取り出すことができます。最後の
@before_scenario()
はGaugeで使えるhook
で、@before_scenario()
で定義されるこの処理は、名前の通りScenarioの前処理として都度実行されます。Gaugeのhook
はこれ以外に、@before_step
,@after_step
,@after_scenario
,@before_spec
,@after_spec
,@before_suite
,@after_suite
があるようです。
まとめ
Gaugeで必要になる2つのスクリプトについて見てきました。Markdownで記載するということで、自由度はありつつも機能は結構制限されるのかなと思っていましたが、結構色々なことができそうです。