変数

はじめに

変数は Robot Framework の重要な機能の一つで、多くの場所で使われています。 最もよく見かけるのは、テストケースやキーワードテーブル中のキーワードの引数でしょう。 その他には、設定テーブルで変数が使えます。 通常、キーワード自体は変数として指定 できません が、 BuiltIn ライブラリのキーワード、 Run Keyword を使えば、同じような効果が得られます。

Robot Framework は独自の変数の仕組みを備えていて、 スカラ型変数, リスト型変数, 辞書型変数 といった変数を、それぞれ ${SCALAR}, @{LIST}, &{DICT} といった記法で扱えます。 そのほか、環境変数%{ENV_VAR} で表すこともできます。

変数は、例えば以下のようなケースで有用です:

  • テストデータ中でよく変わる文字列を扱うとき。変数を使えば、一箇所で変更を行なうだけで済みます。
  • システムや OS に依存しないテストデータを作成したいとき。 ハードコードする代わりに変数を使います (例えば、 ${RESOURCES}c:resources の代わりに、 ${HOST}10.0.0.1:8080 の代わりに)。 変数は、テストを開始するときに コマンドラインでセット できるので、システム固有の変数を簡単に変更できます (--variable HOST:10.0.0.2:1234 --variable RESOURCES:/opt/resources といったように)。 変数を使えば、テストの同じテストを様々な文字列でテストできるので、ローカライズのテストを楽にします。
  • 文字列以外のオブジェクトを引数に渡す必要がある場合は、変数以外の手段がありません。
  • 変数を使えば、たとえ別々のライブラリ上のキーワードであっても、キーワード間で情報を受け渡しできます。あるキーワードからの戻り値を変数に入れ、別のキーワードの引数にすればよいのです。
  • テストデータ中の値が長大だったり、複雑すぎるとき。 例えば、 http://long.domain.name:8080/path/to/service?foo=1&bar=2&zap=42 よりも ${URL} の方が短く書けます。

テストデータ中で、存在しない変数を使おうとすると、その変数を参照したキーワードは失敗します。 変数を使える場所で、変数のような書き方をした文字列をリテラルとして扱いたければ、 ${NAME} のように バックスラッシュでエスケープ する必要があります。

変数タイプ

この節では、様々なタイプの変数について説明します。 変数の作り方は、その後の節で解説します。

Robot Framework の変数は、キーワードと同じように、大小文字を区別せず、スペースやアンダースコアが入っていても無視します。 ただし、グローバルな変数を定義するときは大文字 (${PATH}${TWO WORDS}) を、特定のテストケースやユーザキーワードの中でのみ使う変数は小文字 (${my var}${myVar}) を使うよう勧めます。 加えるならば、もっと重要なのは、大小文字の使い分けには一貫性をもたせることです。

変数名は、変数の型識別文字 ($, @, &, %)、波括弧 ({, }) 、そして、波括弧中に書いた変数名からなります。 似たような変数の記法を持つ言語は他にもありますが、それらとは違い、波括弧は常に必須です。 変数名は、波括弧の間に書きさえすれば、基本的に何にでもできます。ただし、aからzまでのアルファベット、数字、アンダースコアと数字だけにするよう勧めます。 このルールは 拡張変数記法 で変数を使うときの変数名の必須のルールでもあります。

スカラ変数

テストデータ中でスカラ変数を使うと、変数は、その変数に結びついた値に置き換えられます。 スカラ変数は、単純な文字列を扱うときによく使われますが、実際にはリストをはじめ任意のオブジェクトを入れておけます。 スカラ変数の記法、 ${NAME} は、シェルスクリプトや Perl などでも使われていて、大抵のユーザに馴染みのある形式でしょう。

以下の例では、スカラ変数の使い方を示しています。 変数 ${GREET}${NAME} が定義済みで、それぞれの値が Helloworld だとしましょう。 以下の二つのテストケースは同じ結果になります。

*** Test Cases ***
Constants
    Log    Hello
    Log    Hello, world!!

Variables
    Log    ${GREET}
    Log    ${GREET}, ${NAME}!!

テストデータのあるセルにスカラ変数だけが入っていると、スカラ変数は、変数n値そのものに置き換わります。その場合、値は任意のオブジェクトです。 一方、あるセルに、スカラ変数以外に何か (文字列の定数や他の変数) が入っていると、その値は、まず Unicode 文字列に変換され、セルの他の要素と結合されます。 オブジェクトから Unicode 文字列への変換は、 __uinicode__ メソッド (Python の場合。 __unicode__ がなければ __str__ にフォールバックする) か、 toString (Javaの場合) を呼び出して行います。

注釈

キーワードに引数を渡す際、 argname=${var} のような 名前付き引数 にした場合も、変数の値は Unicode 文字列に変換されず、そのまま渡されます。

以下の例は、セルに変数だけを入れた場合と、それ以外のコンテンツも入っている場合の違いを示しています。 まず、変数 ${STR}Hello, world! にセットされていて、 ${OBJ} は以下のような Java オブジェクトだとしましょう:

public class MyObj {

    public String toString() {
        return "Hi, tellus!";
    }
}

それぞれの変数がセットされている状態で、以下のテストデータがあるとします:

*** Test Cases ***
Objects
    KW 1    ${STR}
    KW 2    ${OBJ}
    KW 3    I said "${STR}"
    KW 4    You said "${OBJ}"

このテストデータを実行すると、各キーワードは、それぞれ以下のように引数を受け取ります:

  • KW 1 文字列 Hello, world!
  • KW 2 ${OBJ} に設定したオブジェクト
  • KW 3 文字列 I said "Hello, world!"
  • KW 4 文字列 You said "Hi, tellus!"

注釈

言うまでもなく、Unicode に変換できない変数を Unicode に変換しようとすると失敗します。 例えば、バイト列をキーワードの引数として渡したいときに、 ${byte1}${byte2} のような書き方をすると、この落とし穴に落ちてしまいます。 回避するには、必要な値全体の入った変数を作っておき、一つのセルで渡します。 (e.g. ${bytes}) そうすれば、値がそのままキーワード側に渡るからです。

リスト型変数

変数を ${EXAMPLE} のようにスカラーとして参照した場合、その変数はあるがままの値を表します。 一方、値がリストやリストライクなオブジェクトの場合には、 @{EXAMPLE} のように書くことで、変数をリスト変数として使えます。 キーワードの引数にリスト変数を指定すると、リストの各要素をそれぞれ個別の変数として渡せます。 例えば、変数 @{USER}['robot', 'secret'] という値のとき、以下の二つのテストケースは同じです:

*** Test Cases ***
Constants
    Login    robot    secret

List Variable
    Login    @{USER}

Robot Framework は、どの変数も、内部的には同じ仕組みで保存しており、一つの変数をスカラ型、リスト型、辞書型で扱えるようにしています。 変数をリストとして扱いたいときは、その値は Python のリストか、リストライクなオブジェクトでなければなりません。 Robot Framework では、文字列をリストとしては扱えませんが、タプルや辞書であればリストとして扱えます。

Robot Framework 2.9 までは、スカラ変数とリスト変数は別々に保存されていましたが、リスト変数をスカラとして使ったり、スカラ変数をリストとして扱ったりできました。 そのため、同じ名前のスカラ変数とリスト変数に別々の値が入ってしまうことがあり、よく混乱を招いていました。

リスト変数を他のデータと組み合わせる

リスト変数は他の引数と合わせて使えます。リスト同士でも組み合わせられます。

*** Test Cases ***
Example
    Keyword    @{LIST}    more    args
    Keyword    ${SCALAR}    @{LIST}    constant
    Keyword    @{LIST}    @{ANOTHER}    @{ONE MORE}

リスト変数を、他のデータ(文字列定数や、他の変数)と一緒のセルに入れた場合、そのセルは最終的には各変数の値を文字列にした結果が入ります。 結果は、変数をスカラとして他のデータと一緒のセルにいれたときと同じになります。

リストの個別の要素にアクセスする

リスト変数中の特定の要素にアクセスしたいときには、 @{NAME}[index] のように書きます。 index は、アクセスしたい要素のインデクスです。 インデクスは 0 から数えます。負の数を指定すると、末尾からの順になり、インデクスがリストの要素数より大きい時にはエラーになります。 インデクス部分の内容は値は自動的に整数変換されます。そのため、インデクスには変数も使えます。 インデクスを指定してリストの要素にアクセスした場合、その変数はスカラ変数のように扱えます。

*** Test Cases ***
List Variable Item
    Login    @{USER}[0]    @{USER}[1]
    Title Should Be    Welcome @{USER}[0]!

Negative Index
    Log    @{LIST}[-1]

Index As Variable
    Log    @{LIST}[${INDEX}]

リスト変数を設定テーブルで使う

設定テーブルの 設定 の中には、リスト変数を渡せるものもあります。 ライブラリや変数ファイルのインポート設定の場合、引数にはリスト変数を使えますが、ファイル名には使えません。 同様に、セットアップやティアダウン設定でも、引数にはリスト変数を使えますが、ファイル名には使えません。 タグ関連の設定では、リスト変数を自由に使えます。 リスト変数が指定できない場所では、必ずスカラ変数を使えるようになっています。

*** Settings ***
Library         ExampleLibrary      @{LIB ARGS}    # OK
Library         ${LIBRARY}          @{LIB ARGS}    # OK
Library         @{NAME AND ARGS}                   # うまくいかない
Suite Setup     Some Keyword        @{KW ARGS}     # OK
Suite Setup     ${KEYWORD}          @{KW ARGS}     # OKThis works
Suite Setup     @{KEYWORD}                         # うまくいかない
Default Tags    @{TAGS}                            # OK

辞書変数

上で考察したように、リストの保存されている変数は、 リスト変数 として使うことで、キーワードに引数を渡せます。 同様に、 Python の辞書や、辞書ライクなオブジェクトを保存した変数は、 &{EXAMPLE} の形式で辞書変数として使えます。 そして、この辞書の各値は、キーワードの 名前付き引数 として渡せます。 例えば、変数 &{USER} の値が {'name': 'robot', 'password': 'secret'} のとき、以下の二つの例は同じ結果になります:

*** Test Cases ***
Constants
    Login    name=robot    password=secret

Dict Variable
    Login    &{USER}

辞書変数は Robot Framework 2.9 で登場しました。

辞書変数を他のデータと組み合わせる

辞書変数は、他の引数と組み合わせて使えます。辞書同士の組み合わせも可能です。 仕様上、 名前付き引数の記法 は、位置固定の引数を名前付き引数の前に持ってこなければならないので、辞書変数の後ろには、名前付き引数か、別の辞書変数しか指定できません。

*** Test Cases ***
Example
    Keyword    &{DICT}    named=arg
    Keyword    positional    @{LIST}    &{DICT}
    Keyword    &{DICT}    &{ANOTHER}    &{ONE MORE}

一つのセル中に、他のデータ(文字列や他の変数)と一緒に辞書変数を使った場合、その値は、変数値を文字列に変換して結合した結果になります。 結果的に、一つのセルに、他のデータと一緒にスカラ変数として指定したときと同じ値になります。

辞書変数の個々の要素にアクセスする

辞書中の値は、参照したい値のキーを key としたとき、 &{NAME}[key] の形式で参照できます。 キーは原則文字列ですが、変数を使えば、文字列でない値もキーにできます。 &{NAME}[key] の形式でアクセスした値は、スカラ変数として扱えます。

キーが文字列のとき、 ${NAME.key} というアトリビュート的な記法でも、辞書の要素にアクセスできます。 この記法については、 辞書変数の構築 の節を参照してください。

*** Test Cases ***
Dict Variable Item
    Login    &{USER}[name]    &{USER}[password]
    Title Should Be    Welcome &{USER}[name]!

Key As Variable
    Log Many    &{DICT}[${KEY}]    &{DICT}[${42}]

Attribute Access
    Login    ${USER.name}    ${USER.password}
    Title Should Be    Welcome ${USER.name}!

辞書変数を設定で使う

通常、設定には辞書変数を使えません。 例外はライブラリインポートとセットアップ・ティアダウンの引数に辞書を使う時です。

*** Settings ***
Library        ExampleLibrary    &{LIB ARGS}
Suite Setup    Some Keyword      &{KW ARGS}     named=arg

環境変数

Robot Framework では、 %{ENV_VAR_NAME} という記法で、テストデータの中で環境変数を参照できます。 参照できる値は文字列に限られます。

環境変数は、テストの実行が可能になる前に、OS 側でセットされた値です。 また、実行時に、 OperatingSystem ライブラリの Set Environment Variable キーワードで新たに追加したり、 Delete Environment Variable で削除したりできます。 環境変数はグローバルな値なので、あるテストケースで環境変数をセットすると、他のテストケースでもその値を使うようになります。 ただし、テスト中に環境変数を変更しても、その影響がテスト後まで残ることはありません。

*** Test Cases ***
Env Variables
    Log    Current user: %{USER}
    Run    %{JAVA_HOME}${/}javac

Java のシステムプロパティ

テストを Jython で実行している場合、 環境変数 と同じ記法で Java のシステムプロパティ にアクセスできます。 同じ名前の環境変数とシステムプロパティが存在する場合、環境変数の値が使われます。

*** Test Cases ***
System Properties
    Log    %{user.name} running tests on %{os.name}

変数を定義する

変数は、様々な方法でつくられます。

変数テーブル

よく使うのは、 テストケースファイルリソースファイル の変数テーブルを使う方法です。 変数テーブルの便利なところは、変数を、同じ場所に、テストデータと分けて定義でき、書き方も単純なところです。 一方、短所は、変数の値が文字列になってしまうこと、動的に生成できないことです。 これらの問題を解決したいときは、 変数ファイル を使います。

スカラ変数の定義

変数の代入定義で最も簡単なのは、文字列をスカラ変数に代入するというものです。 この代入文の書き方は、まず変数名を (${} つきで) 最初のセルに書き、第二セルに値を書きます。 第二セルが空なら、値は空文字になります。 値には、別の定義済みの変数も指定できます。

*** Variables ***
${NAME}         Robot Framework
${VERSION}      2.0
${ROBOT}        ${NAME} ${VERSION}

あまりお勧めではありませんが、変数名の直後に = を付けて、変数の代入であることをちょっぴり明確にできます。

*** Variables ***
${NAME} =       Robot Framework
${VERSION} =    2.0

スカラ変数の値が長すぎて記述しづらいときは、複数のカラムや 行に分けて 書けます。 デフォルトの設定では、各セルの値の結合にはスペースを使いますが、最初のセルに SEPARATOR=<sep> を付ければ、セルを結合する文字を変えられます。

*** Variables ***
${EXAMPLE}      This value is joined    together with a space
${MULTILINE}    SEPARATOR=\n    First line
...             Second line     Third line

このように長い文字列を結合できるのは Robot Framework 2.9 からです。 Robot Framework 2.8 では、スカラ変数に複数回値を入れようとするとエラーになり、それ以前のバージョンでは、リストの値が入った変数が生成されていました。

リスト変数の定義

リスト変数の作成も、スカラ変数と同じくらい簡単です。 変数名は変数テーブルの最初のカラムに指定し、変数の値を以降のカラムに指定します。 リスト変数には、ゼロ個の場合も含め、任意の数の要素を入れられます。 たくさんの値を入れる必要があるときは、 複数の行に分割 できます。

*** Variables ***
@{NAMES}        Matti       Teppo
@{NAMES2}       @{NAMES}    Seppo
@{NOTHING}
@{MANY}         one         two      three      four
...             five        six      seven

辞書変数の定義

辞書変数は、リスト変数の定義に似た方法で定義します。 違いは、値の各要素を、 name=value の記法で書くか、または既存の辞書変数で定義するという点です。 同じ名前の複数の要素を定義すると、最後に定義した値が優先します。 キーの中にリテラルの等号を入れたいときは、 = のようにバックスラッシュで エスケープ します。

*** Variables ***
&{USER 1}       name=Matti    address=xxx         phone=123
&{USER 2}       name=Teppo    address=yyy         phone=456
&{MANY}         first=1       second=${2}         ${3}=third
&{EVEN MORE}    &{MANY}       first=override      empty=
...             =empty        key\=here=value

Python の辞書型と比べて、辞書変数は二つの点で拡張されています。 まず、辞書の値にアトリビュートとしてアクセスできます。 つまり、 ${VAR.key} のような、 拡張変数記法 が使えます。 この記法は、キーがアトリビュート名として使える名前であって、かつ、 Python の辞書オブジェクトのアトリビュート名と被らないときにだけ使えます。例えば、 &{USER}[name]${USER.name} でアクセス可能 (この記法では $ が必要なことに注意) ですが、 ${MANY.3} は使えません。

辞書変数のもう一つの特徴は、要素が順序つきで管理されているということです。 つまり、辞書の要素を順次取り出したとき、その並びは常に定義したときと同じ順になるということです。 この振る舞いは、辞書を forループリスト変数 として使った場合などに便利です。 辞書をリスト変数として使うと、その値には辞書のキーが入ります。 例えば、上の例だと、 @{MANY}['first', 'second', 3] という値になります。

変数ファイル

変数ファイルは変数生成の最も強力なメカニズムで、様々な種類の変数を生成できます。 変数ファイルを使えば、任意のオブジェクトを値に持つ変数を作成でき、かつ、動的に変数を生成できます。 変数ファイルの書き方とその使い方は、 リソースファイルと変数ファイル で解説しています。

コマンドラインから変数を設定する

変数はコマンドラインからも設定できます。 --variable (-v) オプションで個別の変数を、 --variablefile (-V) オプションで変数ファイルを指定できます。 コマンドラインで設定した変数は、全てのテストデータファイルでグローバルに使えるほか、テストデータ中の変数テーブルで定義されている変数や、テストデータから取り込んだ他の変数ファイルで定義されている変数の設定値をオーバライドします。

個別の変数設定のオプションの記法は --variable name:value です。 name${} を除いた変数名で、 value が値です。 オプションを繰り返し指定して、複数の値を指定できます。 指定できるのはスカラ値のみで、文字列の値しか指定できません。 特殊文字の中にはコマンドラインで表現しにくいものもありますが、 --escape オプションを使えば エスケープ できます。

--variable EXAMPLE:value
--variable HOST:localhost:7272 --variable USER:robot
--variable ESCAPED:Qquotes_and_spacesQ --escape quot:Q --escape space:_

上の例では、変数は以下のように設定されます:

  • ${EXAMPLE} の値は value です。
  • ${HOST}${USER} が定義されます。 localhost:7272 and robot
  • ${ESCAPED} の値は "quotes and spaces" になります。

変数ファイル の指定は --variablefile path/to/variables.py のように書きます。 変数ファイルについては 変数ファイルの利用 の節を参照してください。 変数がどのように定義されるかは、変数ファイルでどのように変数使われているかによって変わります。

変数ファイルと個別の変数指定の両方で、同じ変数を定義した場合は、後者の方が 優先されます<variable properties and scopes

キーワードの戻り値

キーワードの返す値も、変数に代入できます。 この機能を使えば、異なるテストライブラリのキーワード間であっても相互に情報をやりとりできます。

キーワードの返す値の性質は他の変数とほぼ同じですが、 ローカルスコープ でしか使えません。 従って、例えば、あるテストケースの中で変数を定義しておいて、別のテストケースの中でそのまま参照はできません。なぜなら、一般に、自動テストのテストケースというものは相互に依存関係があってはならないし、別の場所でうっかり値を変更してしまうと、デバッグの困難なエラーを引き起こしてしまうからです。 相応の理由があって、あるテストケースでセットした変数を他のテストケースで使いたいのであれば、後で解説する BuiltIn ライブラリのキーワードを使えます。

スカラ変数に代入する

キーワードの返す値は、 スカラ変数 に代入できます。 以下の例のように、書き方はとても単純です:

*** Test Cases ***
Returning
    ${x} =    Get X    an argument
    Log    We got ${x}!

上の例では、 Get X キーワードの踊り値を変数 ${x} にセットしてから、 Log キーワードで使っています。 変数名のあとの等号 = は (あまり推奨していませんが)、代入を明示するために使えます。 このようなローカルな変数の作成は、テストケースやユーザキーワードで使えます。

値がリストライクな値だったり、 辞書変数 の場合、値をスカラ変数に代入したあとでも、 リスト変数 として参照できます。

*** Test Cases ***
Example
    ${list} =    Create List    first    second    third
    Length Should Be    ${list}    3
    Log Many    @{list}

リスト変数に代入する

キーワードがリストやリストライクなオブジェクトの場合、 リスト変数 に代入できます:

*** Test Cases ***
Example
    @{list} =    Create List    first    second    third
    Length Should Be    ${list}    3
    Log Many    @{list}

Robot Framework の変数は、すべて同じ名前空間に保存されます。 そのため、値を代入したのがスカラ変数であろうがリスト変数であろうが大した違いはありません。 上の例と、ひとつ前の節の例からもそのことが分かります。 大きな違いは、リスト変数を作成するときには、値がリストやリストラライクな性質を備えているか Robot Framework が自動的に検証すること、名前空間に値を保存するときには、もとの値から新たにリストオブジェクトを生成することです。 スカラ値に代入したときには、代入値は検証されず、名前空間に保存されている値も、もとの値(オブジェクト)そのものになります。

辞書変数に代入する

辞書や辞書ライクな値は、 辞書変数 に代入できます:

*** Test Cases ***
Example
    &{dict} =    Create Dictionary    first=1    second=${2}    ${3}=third
    Length Should Be    ${dict}    3
    Do Something    &{dict}
    Log    ${dict.first}

Robot Framework の変数は、すべて同じ名前空間に保存されます。 そのため、スカラ変数に辞書を代入した場合でも、後で必要に応じて辞書として扱えます。 とはいえ、明示的に辞書変数に代入するメリットはいくつかあります。 一つは、リスト変数への代入のときと同様、辞書変数を作成するときには、値が辞書や辞書ライクな性質を備えているか Robot Framework が自動的に検証することです。

より重要なメリットは、辞書変数に代入すると、変数テーブルで 辞書変数を定義 したときと同じく、値が特殊な辞書に変換され保存されるということです。 この特殊な辞書に入っている値は、上の例のように、アトリビュート形式 ${dict.first} でアクセスできます。 辞書変数の値は順序つきで保存されていますが、代入元の辞書が順序つきでなかった場合、代入してできた辞書中の並び順は制御できません。

複数の変数を代入する

キーワードがリストやリストライクなオブジェクトを返す場合、個別の値を複数のスカラ変数に代入したり、スカラ変数とリスト変数の組み合わせに代入したりできます。

*** Test Cases ***
Assign Multiple
    ${a}    ${b}    ${c} =    Get Three
    ${first}    @{rest} =    Get Three
    @{before}    ${last} =    Get Three
    ${begin}    @{middle}    ${end} =    Get Three

上の例で、 Get Three[1, 2, 3] を返すとき、以下のことが起こります:

  • ${a}, ${b}, ${c} の値は、それぞれ 1, 2, 3 です。
  • ${first}1 に、 @{rest}[2, 3] になります。
  • @{before}[1, 2] に、 ${last}3 になります。
  • ${begin} の値は 1, @{middle} の値は [2] で、 ${end}3 です。

戻り値の要素数が代入先のスカラ変数の個数と合わないときはエラーになります。 また、複数代入の場合、使えるリスト変数は1個です。辞書は、複数代入に使えません。

複数代入の仕様は、 Robot Framework 2.9 で少しだけ変更されました。 以前のバージョンは、代入先にリスト変数を置く場合、末尾にしか置けませんでした。 また、以前は、スカラ変数の個数が戻り値の個数より少ない場合も代入ができ、その際、末尾のスカラ変数に、戻り値の残り部分がリストとして入っていました。

Set Text/Suite/Global Variable キーワードを使う

BuiltIn ライブラリの Set Test Variable, Set Suite Variable, Set Global Variable といったキーワードは、テスト実行中に変数を動的に設定できます。

Set Test Variable で設定した変数は、キーワードを呼び出したテストケースのスコープ内のどこからでも参照できます。 ユーザキーワードの中で変数を設定した場合、そのキーワードを使っているテストケースや、同じテストケース内の別のキーワードからもアクセスできます。 他のテストケースからはアクセスできません。

Set Suite Variable で設定した変数は、現在実行中のテススイートのスコープ内のどこからでも参照できます。 従って、このキーワードで定義した変数は、テストデータファイル中で 変数テーブル を使って定義した変数や、 変数ファイル で取り込んだ変数と同じ効果があります。 子となるテストスイートも含め、他のテストスイートには影響しません。

Set Global Variable で変数を設定すると、設定後の全てのテストケース・テストスイートで使えるようになります。 このキーワードで設定した変数は、 --variable--variablefile オプションを使って コマンドラインで変数を指定 した場合と同じ効果を持ちます。 このキーワードは、指定の変数の値をテスト全体で変更してしまうので、慎重に使ってください。

注釈

Set Test/Suite/Global Variable キーワードは、指定の変数を テストケース・スイート・グローバル変数スコープ 上で直接変更し、値を返しません。 一方、 BuiltIn のキーワード Set Variable は、変数のローカルな値を キーワードの戻り値 にセットします。

組み込み変数

Robot Framework には、自動的に定義される組み込み変数があります。

OS 関連の変数

OS 関連の変数は、テストデータを様々なシステムで使う際に、 OS 間の違いを乗り越えやすくします。

OS 関連の組み込み変数
変数名 説明
${CURDIR} テストデータファイルの置かれている場所への絶対パスです。 この変数の値には大小文字の区別があります。
${TEMPDIR} システム固有の一時ディレクトリへの絶対パスです。 UNIX 系のシステムでは /tmp, Windows 系のシステムでは c:\Documents and Settings\<user>\Local Settings\Temp となるのが一般的です。
${EXECDIR} テストの実行を開始したディレクトリへの絶対パスです。
${/}
システム固有のディレクトリ区切り文字です。 UNIX 系のシステムでは
/ , Windows 系のシステムでは \ です。
${:}
システム固有のパス要素区切り文字です。 UNIX 系のシステムでは
:, Windows 系では ; です。
${\n} システム固有の改行文字です。 UNIX 系のシステムでは \n で、Windows 系では \r\n です。バージョン 2.7.5 で登場しました。
*** Test Cases ***
Example
    Create Binary File    ${CURDIR}${/}input.data    Some text here${\n}on two lines
    Set Environment Variable    CLASSPATH    ${TEMPDIR}${:}${CURDIR}${/}foo.jar

数値変数

以下の例のように、変数の記法を使って、整数や浮動小数点数のオブジェクトを生成できます。 この記法は、キーワードの引数に、「数値をあらわす文字列」ではなく「数値そのもの」を渡さねばならない場合に使います。

*** Test Cases ***
Example 1A
    Connect    example.com    80       # Connect の引数は二つの文字列になる

Example 1B
    Connect    example.com    ${80}    # Connect の引数は文字列と整数になる

Example 2
    Do X    ${3.14}    ${-1e-4}        # Do X の引数は数値 3.14 と数値 -0.0001 になる

整数の数値変数を作成するときは、 0b, 0o, 0x プレフィクスを使って、それぞれ 2 進、8進、16進数を表せます。この記法では、大小文字を区別しません。

*** Test Cases ***
Example
    Should Be Equal    ${0b1011}    ${11}
    Should Be Equal    ${0o10}      ${8}
    Should Be Equal    ${0xff}      ${255}
    Should Be Equal    ${0B1010}    ${0XA}

ブール値と None/null を表す変数

ブール型の値と Python の None, Java の null も、変数の記法で生成できます。

*** Test Cases ***
Boolean
    Set Status    ${true}               # Set Status にはブール型の True が渡される
    Create Y    something   ${false}    # Create Y には文字列とブールの False が渡される

None
    Do XYZ    ${None}                   # Do XYZ には Python の None が渡される

Null
    ${ret} =    Get Value    arg        # Get Value が Java の null を返すか確かめる
    Should Be Equal    ${ret}    ${null}

ブール値と None/null の変数記法には、大小文字の区別がないので、 ${True}${true} は同じです。 また、Jython インタプリタでテストを実行する際、 Jython は自動的に ${None}${null} を相互に変換するため、 ${None}${null} は同義です。

スペースと空の値を表す変数

スペースと空の文字列を、それぞれ ${SPACE}${EMPTY} で表せます。 これらの変数は、例えばバックスラッシュで スペースや空のセルをエスケープ せねばならないような状況で便利です。 複数のスペースかを表現したいときは、 ${SPACE * 5} のような 拡張変数表記 を使えます。 以下の例の Should Be Equal の二つの引数はどちらも同じ値になりますが、前者の変数を使った表記の方が、後者のバックスラッシュよりも分かりやすいはずです。

*** Test Cases ***
One Space
    Should Be Equal    ${SPACE}          \ \

Four Spaces
    Should Be Equal    ${SPACE * 4}      \ \ \ \ \

Ten Spaces
    Should Be Equal    ${SPACE * 10}     \ \ \ \ \ \ \ \ \ \ \

Quoted Space
    Should Be Equal    "${SPACE}"        " "

Quoted Spaces
    Should Be Equal    "${SPACE * 2}"    " \ "

Empty
    Should Be Equal    ${EMPTY}          \

この他にも、空の リスト変数 を表す @{EMPTY} や、空の 辞書変数 を表す &{EMPTY} があります。 基本的に、これらの変数には中身がないので、テストデータ中で使っても消えてしまいます。 空のリスト・辞書変数が意味をもつのは、 テストテンプレート 中で、 テンプレートキーワードを引数なしで使いたい ときや、スコープ中のリスト変数や辞書変数をオーバライドしたいときです。 @{EMPTY}&{EMPTY} の中身は変更できません。

*** Test Cases ***
Template
    [Template]    Some keyword
    @{EMPTY}

Override
    Set Global Variable    @{LIST}    @{EMPTY}
    Set Suite Variable     &{DICT}    &{EMPTY}

注釈

@{EMPTY} は Robot Framework 2.7.4 で、 &{EMPTY} は 2.9 で登場しました。

自動変数

変数の中には、自動生成され、テストデータの中で使えるものがあります。 この中には、テストの実行中に値が変わっていくものもあれば、状況によって使えないものもあります。 通常、自動変数の値を変更しても、元の値には影響しません。 ただし、一部の値は、 BuiltIn ライブラリのキーワードを使って動的に変更できます。

利用可能な自動変数
変数 説明 有効範囲
${TEST NAME} 現在実行中のテストケース名 テストケース
@{TEST TAGS}

現在実行中のテストケースのタグ、アルファベット順。 Set TagsRemove Tags で、動的に

変更可能。
テストケース
${TEST DOCUMENTATION} 現在実行中のテストケースのドキュメント。 Set Test Documentation で動的に変更可。 Robot Framework 2.7 以降。 テストケース
${TEST STATUS} 現在実行中のテストケースの状態、 PASS または FAIL 。 テストのティアダウン
${TEST MESSAGE} 現在実行中のテストケースのメッセージ。 テストのティアダウン
${PREV TEST NAME} 直前に実行したテストケースの名前。 まだ実行していなければ空文字列 どこでも
${PREV TEST STATUS} 直前に実行したテストケースの状態、 PASSまたはFAIL。 まだ実行していなければ空文字列 どこでも
${PREV TEST MESSAGE} 直前のテストが失敗していた場合、そのエラーメッセージ どこでも
${SUITE NAME} 現在実行中のテストスイートの完全な名前。 どこでも
${SUITE SOURCE} テストスイートのファイルまたはディレクトリの絶対パス どこでも
${SUITE DOCUMENTATION} 現在実行中のテストスイートのドキュメント。 Set Suite Documentation で動的に変更可能。 Robot Framework 2.7 以降 どこでも
&{SUITE METADATA} 現在実行中のテストスイートのメタデータ。 Set Suite Metadata で動的に変更可能。 Robot Framework 2.7.4 以降 どこでも
${SUITE STATUS} 現在実行中のテストスイートの状態。 PASS または FAIL。 スイートのティアダウン
${SUITE MESSAGE} 現在実行中のテストスイートの全メッセージ。 テスト結果統計も含む スイートのティアダウン
${KEYWORD STATUS} 現在実行中のキーワードの状態。 PASS または FAIL。 Robot Framework 2.7 以降 ユーザキーワードのティアダウン
${KEYWORD MESSAGE} 現在実行中のキーワードのエラーメッセージ。 Robot Framework 2.7 以降 ユーザキーワードのティアダウン
${LOG LEVEL} 現在の ログレベル 。 Robot Framework 2.8 以降 どこでも
${OUTPUT FILE} テスト結果出力ファイル の絶対パス どこでも
${LOG FILE} ログファイル の絶対パス。 ログファイルを生成しないときは文字列 NONE どこでも
${REPORT FILE} レポートファイル の絶対パス。 レポートファイルを生成しないときは文字列 NONE どこでも
${DEBUG FILE} デバッグファイル の絶対パス。 デバッグファイルを生成しないときは文字列 NONE どこでも
${OUTPUT DIR} 出力ディレクトリ の絶対パス どこでも

テストスイート関連の変数、 ${SUITE SOURCE}, ${SUITE NAME}, ${SUITE DOCUMENTATION}, &{SUITE METADATA} は、テストライブラリや変数ファイルのインポートの時点で使えます。 ただし、 Robot Framework 2.8 と 2.8.1 では、不具合があったため使えません。 その他の変数は、 import 時に変数の解決ができません。

変数の優先順位とスコープ

変数は、どこで定義されたかによって、優先順位が異なります。 また、利用できるスコープも変わります。

変数の優先順位

コマンドラインで設定した変数

コマンドラインで設定した引数 は、全ての変数の中で最も高い優先順位をもち、テストの実行前に設定されます。 コマンドラインで設定した値は、テストケースファイルの変数テーブル上の変数や、テストデータ中でインポートしたリソース・変数ファイル上の変数の設定値を上書きします。

個別の変数を設定するオプション (--variable) は、 変数ファイル を設定するオプション (--variablefile) による設定を上書きします。 同じ変数の設定を複数回繰り返した場合、最後に指定した値を優先します。 この機能を使えば、デフォルトの値を スタートアップスクリプト に書いておき、コマンドラインからオプションを指定してオーバライドできます。 ただし、複数の変数ファイルに同じ名前の変数が指定されていた場合、ファイル間では、最初に定義した内容が最も高い優先順位を持つので注意してください。

テストケースファイルの変数テーブル

テストケースファイルの 変数テーブル で作成した変数は、そのファイル上の全てのテストケースで使えます。 変数テーブル上の変数は、他からインポートしたリソースや変数ファイルの変数をオーバライドします。

変数テーブルで作成した変数は、そのテーブルがあるファイルの他の全てのテーブルで使えます。 つまり、設定テーブルに変数を使うことができ、例えば、他のリソースファイルや変数ファイルをインポートしたいときに、それらを変数で表すことさえできます。

リソースファイルや変数ファイルからインポートした変数

リソースファイルや変数ファイル からインポートした変数は、テストデータ上で作成した変数の中ではもっとも低いの優先度を持ちます。 リソースファイルと変数ファイルのとの間には、優先順位の上下はありません。 リソースファイルや変数ファイルが同じ変数を定義していた場合、最初にインポートしたファイルの定義を使います。

リソースファイルが別のリソースファイルや変数ファイルをインポートしている場合、インポート元の変数の定義が優先されます。 インポート先のリソースファイルがさらに別のファイルをインポートしている場合、インポート先も含む全ての変数を使えるようになります。

リソースファイルや変数ファイルでインポートした変数の値を使って、インポート元の変数テーブルを定義することはできません。 これは、変数テーブルが、設定テーブルよりも先に処理され、その後で、リソースファイルや変数ファイルがインポートされるからです。

テスト実行中に設定される変数

キーワードの戻り値Set Test/Suite/Global Variable で実行中にセットした変数は、スコープの中では常に変数の値をオーバライドします。 その意味では、最も高い優先度ともいえますが、スコープから出れば、既存の変数に対して何ら影響力を保ちません。

組み込み変数

${TEMPDIR}${TEST_NAME} のような 組み込み変数 は、他の全ての変数よりも高い優先順位を持ちます。 これらの変数は、変数テーブルやコマンドラインでオーバライドできない上に、テストの実行中にリセットされることもあります。 数値変数 は例外で、その値は、他で予めセットされていない限り動的に解決されます。 数値変数の値はオーバライドできますが、そうすべきではありません。 また、 ${CURDIR} は、テストデータの処理中に随時変更されるという点で特殊です。

変数のスコープ

変数は、どこで作成したかによって、グローバル・テストスイート・テストケース・ローカルのいずれかのスコープをもちます。

グローバルスコープ

グローバルな変数は、テストデータのどこからでも参照できます。 グローバルな変数は、 --variable オプションや --variablefile オプションで コマンドラインで変数を設定 してできますが、テストデータ中で BuiltIn キーワードの Set Global Variable を使うことでも生成できます。 また、 組み込み変数 もグローバルな変数です。

グローバルな変数の名前には、大文字を使うよう推奨します。

テストスイートスコープ

テストスイートスコープの変数は、その変数を定義したり、インポートしたテストスイート内のどこからでも参照できます。 テストスイートの変数は、変数テーブルや、 リソースファイルや変数ファイル からインポートできるほか、テストの実行時に、 BuiltIn キーワードの Set Suite Variable を使うことでも生成できます。

テストスイートの変数は、 再帰性がない 、すなわち、上位のテストスイートで定義した変数は、より下位のテストスイートで 使えない という特徴があります。 テストスイートをまたいで変数を共有したいときは、 リソースファイルや変数ファイル を介する必要があります。

テストスイートの変数は、テストスイート内ではグローバルな変数のようにみなせるので、名前には大文字を使うよう推奨します。

テストケーススコープ

テストケーススコープの変数は、テストケースと、そのテストケースから呼び出したキーワードの中でしか参照できません。 初期状態では、テストケースのスコープには、何の変数もありませんが、 BuiltIn キーワードの Set Test Variable を使うことで生成できます。

テストケーススコープの変数もまた、テストケース内ではグローバルな変数のようにみなせるので、名前には大文字を使うよう推奨します。

ローカルスコープ

テストケースやユーザキーワードには、ローカルな変数スコープがあります。 このスコープの変数は、他のテストやキーワードからは見えません。 ローカルな変数は、キーワードを実行したときの 戻り値 や、ユーザキーワードが 引数 を受け取った時に生成されます。

ローカルな変数には、小文字の名前を使うよう推奨します。

注釈

Robot Framework 2.9 までは、ローカルスコープの変数が、 より下位のユーザキーワードから見えてしまう という問題がありました。 これは設計意図に反した挙動なので、以前のバージョンでも、値を下位のキーワードに渡したいときは、引数などで明に渡すようにしてください。

変数の高度な使い方

拡張変数記法

拡張変数記法は、 ${object.attribute} のような書き方で、変数に代入されたオブジェクトのアトリビュートにアクセスするための記法です。 この書き方は、スカラ変数でもリスト変数でも使えますが、主に前者の場合に便利です。

拡張変数記法は強力な機能ですが、注意深く使ってください。 とはいえ、アトリビュートへのアクセス自体はさほど問題ではありません。 それに、一つの変数に一つのオブジェクトが入っていて、そのオブジェクトが複数のアトリビュートを備えている方が、たくさんの変数をもたねばならないよりベターです。 一方で、メソッドの呼び出しは、とりわけ引数と組み合わせてつかった場合などに、テストデータを複雑にし、理解を妨げます。 メソッドの呼び出しのためにテストが複雑になりそうなときは、コードをテストライブラリに移すよう勧めます。

以下の例では、拡張変数記法のよくある使い方を示しています。 まず、以下のような 変数ファイル とテストケースがあるとしましょう:

class MyObject:

    def __init__(self, name):
        self.name = name

    def eat(self, what):
        return '%s eats %s' % (self.name, what)

    def __str__(self):
        return self.name

OBJECT = MyObject('Robot')
DICTIONARY = {1: 'one', 2: 'two', 3: 'three'}
*** Test Cases ***
Example
    KW 1    ${OBJECT.name}
    KW 2    ${OBJECT.eat('Cucumber')}
    KW 3    ${DICTIONARY[2]}

このテストデータを実行すると、各々のキーワードは:

  • KW 1Robot という文字列
  • KW 2Robot eats Cucumber という文字列
  • KW 3two という文字列

を受け取ります。

拡張変数記法の値は、以下の順番に評価されます:

  1. 変数名を、拡張変数記法ではなく、普通の変数として、完全な変数名が一致するものが定義されていないか探します。 一致する変数がないときにのみ、拡張変数記法として評価します。
  2. 拡張記法のベースとなる変数名を生成します。変数名本体は、変数の { の後から、最初の非英数文字までの文字列です。 例えば、 ${OBJECT.name} のベース変数名は OBJECT, ${DICTIONARY[2]}) なら DICTIONARY です。
  3. ベース変数名に対応する変数を探します。 一致する変数名がなければ、例外が送出され、テストケースは失敗します。
  4. 波括弧中の式を、 Python の式として評価します。 このとき、ベース変数名は、実際の値に置き換わります。 記法の誤りや、アトリビュートが存在しないなどの理由で式の評価に失敗すると、例外が送出され、テストケースは失敗します。
  5. 評価の結果で変数全体を置き換えます。

Java で実装したオブジェクトの場合、拡張変数記法を使って、いわゆる bean プロパティにアクセスできます。 例えば、 getName というメソッドを備えたオブジェクトが変数 ${OBJ} に入っている場合、 ${OBJ.name} は、 ${OBJ.getName()} と同じです。 先の例で使った Python オブジェクトの Java 版を書くと、以下のようになります:

public class MyObject:

    private String name;

    public MyObject(String name) {
        name = name;
    }

    public String getName() {
        return name;
    }

    public String eat(String what) {
        return name + " eats " + what;
    }

    public String toString() {
        return name;
    }
}

文字列や数値型を始め、Python の標準データ型には様々なメソッドがあり、拡張変数記法で明示的・非明示的に扱えます。 効果的に使えば、一時変数を生成する手間を省けるのでとても便利なのですが、濫用した結果、暗号のようなテストデータを書いてしまうこともあるので注意してください。 以下はよい使い方の例です。

*** Test Cases ***
String
    ${string} =    Set Variable    abc
    Log    ${string.upper()}      # Logs 'ABC'
    Log    ${string * 2}          # Logs 'abcabc'

Number
    ${number} =    Set Variable    ${-2}
    Log    ${number * 10}         # Logs -20
    Log    ${number.__abs__()}    # Logs 2

通常の Python のコードだと、 number.__abs__() と書くより abs(number) と書くのが適切ですが、後者は拡張変数記法では使えません。 拡張変数記法では、変数名を先頭に置かねばならないからです。 テストデータの中に __xxx__ メソッドを使うこと自体すでに微妙で、こうしたロジックはテストライブラリに移すのがベターです。

拡張変数記法は、 リスト変数 でも使えます。 例えば、変数 ${EXTENDED} に入っているオブジェクトが attribute というアトリビュートを持ち、このアトリビュートの値がリストであるような場合は、 @{EXTENDED.attribute} のようにリスト変数で扱えます。

拡張変数記法の代入

Robot Framework 2.7 からは、スカラ変数に保存されたオブジェクトのアトリビュートを、 キーワードの戻り値拡張変数記法 のバリエーションを使ってセットできるようになりました。 前節で示した変数 ${OBJECT} を例にとると、そのアトリビュートは以下の例のようにしてセットできます。

*** Test Cases ***
Example
    ${OBJECT.name} =    Set Variable    New name
    ${OBJECT.new_attr} =    Set Variable    New attribute

拡張変数記法の代入は、以下のルールに従って評価されます:

  1. 代入先の値はスカラー変数でなければならず、変数中に少なくとも一つのドットが必要です。 それ以外の場合は、拡張変数記法の代入は行われず、普通の変数代入が行われます。
  2. 代入先の変数名と完全に一致する変数名 (上の例だと OBJECT.name という変数名) の変数が存在する場合、その変数への代入を行い、拡張変数記法の代入は行いません。
  3. ベースの変数名を生成します。変数名の本体部分は、 ${ の後から最後のドット出現位置までの全ての文字かららなります。 例えば、 ${OBJECT.name} の場合は OBJECT, ${foo.bar.zap} なら foo.bar です。 後者の例からわかるように、ベース変数名自体が拡張変数表記のときもあります。
  4. アトリビュートの名前を、最後のドットから閉じ括弧 } までの文字で構成します。 例えば、 ${OBJECT.name} のアトリビュート名部分は name です。 アトリビュート名部分が、アルファベットまたはアンダースコアで開始しておらず、かつ英数文字以外の文字を含む場合、無効なアトリビュート名とみなし、拡張変数記法の代入を行いません。 その場合、アトリビュート部分も含めた全体を変数名として、新たな変数を生成します。
  5. ベース変数名に対応する変数を探します。 該当する変数がみつからない場合、拡張変数記法の代入を行いません。 その場合、アトリビュート部分も含めた全体を変数名として、新たな変数を生成します。
  6. 見つかった変数の値が文字列型や数値型だった場合、拡張変数記法の代入を行いません。 その場合、アトリビュート部分も含めた全体を変数名として、新たな変数を生成します。 Python の文字列型や数値型にはあらたなアトリビュートを代入できないからです。
  7. 上記のルールに全て合致していれば、ベースの変数にアトリビュートを設定します。 何らかの理由でアトリビュートを設定できなければ、例外を送出し、テストは失敗します。

注釈

変数を キーワードの戻り値 で代入したときと違い、拡張変数代入で変更した値は、現在のスコープ外でも有効です。 新たな変数は生成されませんが、既存の変数の内部状態が変わるので、その変数を参照しているテストやキーワードにも影響が及びます。

変数中の変数

変数の中にも、変数を使えます。 変数名が入れ子になっている場合、内側から順に変数を解決していきます。 例えば、 ${var${x}} という変数に対しては、まず ${x} を解決します。 仮に ${x} の値が name だとすると、最終的に、この変数の値は ${varname} の値となります。 入れ子は何重にもでき、いくつでも入れ子にできますが、入れ子の内側のいずれか一つでも変数が存在しない場合、最も外側の変数解決も失敗します。

以下の例では Do X は、 Get Name キーワードが johnjane のいずれかを返すとき、それぞれ ${JOHN HOME}${JANE HOME} を返します。
Get Name キーワードがその他の値を返すと、 ${${name} HOME} の解決に失敗します。
*** Variables ***
${JOHN HOME}    /home/john
${JANE HOME}    /home/jane

*** Test Cases ***
Example
    ${name} =    Get Name
    Do X    ${${name} HOME}