Robot Frameworkの変数ファイルについて

この記事は「Robot Framework Advent Calendar 2017 - Qiita」の10日目の記事です。

 
前回、Robot Frameworkにおける変数定義と優先順について書きました。

そこでは 変数ファイル については省略していたため、今回は変数ファイルについて記載します。

 
目次

 

環境

  • Robot Framework 3.0.2

 

変数ファイルとは

公式ドキュメントではこちらに記載があります。

 
Robot Frameworkでは、Pythonで書いた

をRobot Frameworkの変数として扱えます。それらが書かれたファイルのことを変数ファイルと呼びます。

Pythonで書けるので、リソースファイルと比べて柔軟な定義ができます。

 
今回はユーザガイドに従い、いろいろと試してみます。

 

変数ファイルをテストケースファイルで読み込むには

テストケースファイルのSettingsで Variables を使い変数ファイルを指定します。

以下の例では、テストケースファイルと同じディレクトリにある variable_file.py を変数ファイルとして読み込み、Robot Frameworkの変数として追加します。

*** Settings ***
Variables    variable_file.py

 

いろいろな変数ファイル中の定義

変数ファイルではいくつかの方法でRobot Framework用変数を定義できます。

 

Pythonの変数(定数)

Pythonファイルに

FOO = 'foo'

Pythonの変数(定数)を定義すると、Robot Frameworkの変数となります。

テストケースを

*** Test Cases ***
Pythonの定数
    log to console  ${FOO}

として実行すると、

Pythonの定数    foo

と出力されます。

 

Pythonの辞書

Pythonの辞書も同様です。

BAR = {'ham': 'spam'}

と変数ファイルを定義します。

テストケースを

Pythonの辞書
    log to console  ${BAR}

として実行した場合、

Pythonの辞書    {'ham': 'spam'}

Robot Frameworkの辞書型の変数となります。

 

Pythonの辞書で、定数名にプレフィックスを付けた場合

Pythonの辞書型変数名にプレフィックスを付けると、明示的に辞書型の定数として定義できます。

プレフィックス__変数名 という形であり、Robot Frameworkではプレフィックスが取れた変数名として認識されます。

以下の例の場合、Robot Frameworkでは BAZ として認識されます。

DICT__BAZ = {'egg': 'spam'}

 
また、プレフィックスを付けると、Robot Frameworkで . を使ったアクセスができます。

プレフィックスの有無での挙動を比較するため、それぞれの辞書を用意します。

BAR = {'ham': 'spam'}
DICT__BAZ = {'egg': 'spam'}

テストケースを

Pythonの辞書でプレフィックス無しの場合keyアクセスができない
    log to console  ${BAR.ham}

Pythonの辞書でプレフィックス付の場合keyアクセスができる
    log to console  ${BAZ.egg}

として実行した場合、

Pythonの辞書でプレフィックス付    {'egg': 'spam'}
Pythonの辞書でプレフィックス付    | PASS |
------------------------------------------------------------------------------
Pythonの辞書でプレフィックス無しの場合keyアクセスができない    | FAIL |
Resolving variable '${BAR.ham}' failed: AttributeError: 'dict' object has no attribute 'ham'

となります。

 

プレフィックスがないと変数名が重複する場合

Pythonではプレフィックスを付けた変数と付けない変数は別モノとなるため、重複していることに気づかないかもしれません。

例えば、Pythonコード中に以下を書いていたとしてます。

DICT__DUPLICATE = {'dup': 1}
DUPLICATE = {'dup': 2}

テストケースを

変数が重複していた場合
    log to console  ${DUPLICATE}

として実行した場合

変数が重複していた場合    {'dup': 1}

となります。

最初に定義されていたPythonの変数がRobot Frameworkの変数として使われます。

 

Pythonの関数の戻り値

Pythonの関数の戻り値をRobot Frameworkの変数として設定することもできます。

def get_result():
    return 1


RESULT = get_result()

テストケースで

Pythonの関数の結果を設定した変数
    log to console  ${RESULT}

として実行した場合

Pythonの関数の結果を設定した変数    1

となります。

Pythonの関数そのもの

Pythonの関数そのものも、Robot Frameworkの変数として定義できます。

def get_random():
    return random.randint(0, 20)

テストケースにて

Pythonの関数そのもの
    log to console  ${get_random}

として実行した場合、

Pythonの関数そのもの    <function get_result at 0x10650d400>

となります。

 

アンダースコアで始まるPythonの関数

関数名が _ から始まる場合、Robot Frameworkの変数としては使えません。

def _under_score_func():
    pass

テストケースにて

Pythonの関数でアンダースコア始まりのものは対象外
    log to console  ${_under_score_func}

として実行した場合、

Pythonの関数でアンダースコア始まりのものは対象外    FAIL |
Variable '${_under_score_func}' not found.

となります。

 

Pythonの定数や関数のうち、除外したいものについて

今まで見てきた通り、Pythonファイルに書かれたものはRobot Frameworkの変数として使用できます。

ただ、アンダースコア始まりの関数を除き、Pythonファイルで定義されているものはRobot Frameworkの変数となってしまいます。それでは不都合があるかもしれません。

その場合、 __all__ を使うことで、Robot Frameworkの変数として扱いたいものを絞り込めます。

例えば、

__all__ = ['include_func', 'INCLUDE_VARIABLE']

INCLUDE_VARIABLE = 'foo'
EXCLUDE_VARIABLE = 'bar'


def include_func():
    pass


def exclude_func():
    pass

とします。

テストケースにて

Pythonの定数で__all__にあるものは対象
    log to console  ${INCLUDE_VARIABLE}

Pythonの定数で__all__に無いものは対象外
    log to console  ${EXCLUDE_VARIABLE}

Pythonの関数で__all__にあるものは対象
    log to console  ${include_func}

Pythonの関数で__all__に無いものは対象外
    log to console  ${exclude_func}

として実行した場合、

Pythonの定数で__all__にあるものは対象    foo
Pythonの定数で__all__にあるものは対象    | PASS |
----------------------------------------
Pythonの定数で__all__に無いものは対象外    | FAIL |
Variable '${EXCLUDE_VARIABLE}' not found. Did you mean:
    ${INCLUDE_VARIABLE}
----------------------------------------
Pythonの関数で__all__にあるものは対象    <function include_func at 0x10650d510>
Pythonの関数で__all__にあるものは対象    | PASS |
----------------------------------------
Pythonの関数で__all__に無いものは対象外    | FAIL |
Variable '${exclude_func}' not found.

となります。

 

Pythonのクラス変数・インスタンス変数を使う

Pythonのクラス変数・インスタンス変数も使えます。

ただし、

  • クラスのインタンスは使用不可
  • Pythonのクラス変数・インスタンス変数を扱うには、クラス名とクラスを定義してあるファイル名の一致が必要

です。

例えば、Pythonファイルに2つのクラスを定義します。

variable_file_class.py

class variable_file_class:
    class_val = 'python'

    def __init__(self):
        self.instance_val = 'self val'


instance_from_class = variable_file_class()


class diff_variable_file:
    diff_class_val = 'diff class'

    def __init__(self):
        self.diff_instance_val = 'self diff val'

テストケースにて

Pythonのクラスをインスタンス化して変数に設定したものは参照できない
    log to console  ${instance_from_class}

Pythonクラスのクラス変数を使う
    log to console  ${class_val}

Pythonクラスのインスタンス変数を使う
    log to console  ${instance_val}

Pythonクラスはファイル名と同じでないとクラス変数を参照できない
    log to console  ${diff_class_val}

Pythonクラスはファイル名と同じでないとインスタンス変数を参照できない
    log to console  ${diff_instance_val}

として実行した場合、

Pythonのクラスをインスタンス化して変数に設定したものは参照できない    | FAIL |
Variable '${instance_from_class}' not found.
----------------------------------
Pythonクラスのクラス変数を使う    python
Pythonクラスのクラス変数を使う    | PASS |
----------------------------------
Pythonクラスのインスタンス変数を使う    self val
Pythonクラスのインスタンス変数を使う    | PASS |
----------------------------------
Pythonクラスはファイル名と同じでないとクラス変数を参照できない     | FAIL |
Variable '${diff_class_val}' not found.
----------------------------------
Pythonクラスはファイル名と同じでないとインスタンス変数を参照できない    | FAIL |
Variable '${diff_instance_val}' not found.

となります。

 

YAMLファイルからの読み込み

変数ファイルはYAMLファイルとしても用意できます。

なお、YAMLファイルを変数ファイルとして使う場合は、PyYAMLのインストールが必要です。

pip install pyyaml

変数ファイルをYAML

yaml_dict:
    one: 1
    two: 2

と記載し、

YAMLファイルから読み込む
    log to console  ${yaml_dict}

と使った場合です。

実行結果は

YAMLファイルから読み込む    {'one': 1, 'two': 2}

です。

 

特殊な関数 get_variables() について

Robot Frameworkの変数ファイルでは、特殊な関数 get_variables() が使えます。

例えば、変数ファイルにて

def get_variables():
    return {
        'SPECIAL_FUNC': {'hoge': 'fuga'}
    }

とします。

テストケースにて

get_variablesを使う
    log to console  ${SPECIAL_FUNC}

として実行した場合、

get_variablesを使う    {'hoge': 'fuga'}

となります。

 
なお、 get_variables() 関数自体を変数として使うことはできません。

テストケースにて

get_variables自体は取れない
    log to console  ${get_variables}

として実行した場合、

get_variables自体は取れない    | FAIL |
Variable '${get_variables}' not found.

となります。

 

気になる get_variables() の挙動について

発生条件などがわかっていないので気になったというメモ書きです。

get_variables() を使った変数ファイルと、それ以外の変数ファイルを同時に読み込んだ場合、get_variables() の変数以外が

Pythonの定数    | FAIL |
Variable '${FOO}' not found.

のようになったことがありました。

復活した原因もよくわかっていません。

そのため、もし同じような事象が発生した場合は、 get_variables() を含む変数ファイルを外してみると良いかもしれません。

 

ソースコード

GitHubに上げました。 variables_samples/variable_files ディレクトリの中が今回のファイルです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples