FakerLibraryを使って、Robot Framework向けのダミーデータを作成する

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

テストデータを作成する時、何かしらのダミーデータが必要になることがあります。

例えば、Pythonでは Faker などのライブラリを使ってダミーデータを作成します。
joke2k/faker: Faker is a Python package that generates fake data for you.

 
Robot Frameworkでもダミーデータを作る方法がないかを探したところ、Fakerのラッパーである FakerLibrary がありました。

そこで今回は、FakerLibraryを試してみます。

 
目次

 

環境

  • Python 3.6.3
  • Robot Framework 3.0.2
  • FakerLibrary 4.2.0

 
FakerLibraryのインストールはpipで行います。

pip install robotframework-faker

 
なお、以下のissueがクローズされているため、Python3でも問題なく使えます。
Python 3.x compatibility · Issue #20 · guykisel/robotframework-faker

 

FakerLibraryの参照

FakerLibraryのドキュメントを見たところ、いろいろな項目のダミーデータが用意されているようでした。

また、Importing欄に locale がありました。fakerのラッパーだとしたら日本語が扱えそうです。

そこで、

*** Settings ***
Library  FakerLibrary  locale=ja_JP

として FakerLibrary を参照することにしました。

 

FakerLibraryで日本語のダミーデータを作成する

以下のRobot Frameworkのテストコードを作成してみました。

*** Settings ***
Library  FakerLibrary  locale=ja_JP


*** Test Cases ***
個人のフェイクデータを作成する
    # "FakerLibrary" というプレフィックスがなくても動作する
    ${address} =  FakerLibrary.Address
    ${city} =  FakerLibrary.City
    ${first_name} =  FakerLibrary.First Name
    ${last_name} =  FakerLibrary.Last Name
    ${name} =  FakerLibrary.Name

    Log To Console  ${\n}${address}${\n}${city}${\n}${first_name}${\n}${last_name}${\n}${name}

    ${email} =  FakerLibrary.Email
    ${tel} =  FakerLibrary.Phone Number

    # special_chars, digits, upper_case, lower_case の設定も可能
    ${password} =  FakerLibrary.Password  length=15
    ${postcode} =  FakerLibrary.Postcode

    Log To Console  ${\n}${email}${\n}${password}${\n}${tel}${\n}${postcode}${\n}${zipcode}


会社のフェイクデータを作成する
    ${company} =  FakerLibrary.Company
    ${email} =  FakerLibrary.Company Email

    # サフィックスはIncであり、(株)などではない
    ${suffix} =  FakerLibrary.Company Suffix

    Log To Console  ${\n}${company}${\n}${email}${\n}${suffix}


適当な文を作成する
    ${paragraph} =  FakerLibrary.Paragraph
    Log To Console  ${paragraph}

 
実行してみます。

$ robot test_faker.robot 
======================
Test Faker
======================
個人のフェイクデータを作成する    ...
新潟県西多摩郡檜原村虎ノ門虎ノ門ヒルズ森タワー3丁目125号
山武郡九十九里町
香織
工藤
木村 和也
個人のフェイクデータを作成する    ...
unotakuma@hotmail.com
+z4d2Zdy8%aYyyx
090-3496-6948
46207
個人のフェイクデータを作成する    | PASS |
--------------------------------
会社のフェイクデータを作成する    ...
株式会社 伊藤
unoakira@kato.com
LLC
会社のフェイクデータを作成する    | PASS |
--------------------------------
適当な文を作成する    .
明らかにするサワーテント索引屋根裏移動暖かい。見落とす試してみるヒールホイール。
適当な文を作成する    | PASS |

日本語のテストデータができました。

 

アンドキュメントな郵便番号の出力について

先ほどの結果をよく見ると、 FakerLibrary.Postcode が5桁で出力されていました。日本の郵便番号とは異なっているようです。

 
fakerでは日本の郵便番号はどうなっているのだろうと思い調べたところ、以下の記事がありました。
Pythonのfakerで日本語テストデータを生成する - Qiita

記事によると zipcode が日本の郵便番号のようでした。

 
そこでドキュメントにはなかったものの、 zipcode を指定してみます。

 

*** Test Cases ***
個人のフェイクデータを作成する
#...
    ${postcode} =  FakerLibrary.Postcode
    ${zipcode} =  FakerLibrary.Zipcode

 
実行してみます。

46207
153-4563
個人のフェイクデータを作成する    | PASS |

日本の郵便番号っぽいのが出力されました。

 

ソースコード

GitHubに上げました。faker_sample ディレクリの中が今回のものです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

Robot Framework + SSHLibraryで、SSHのテストをする

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

Robot Frameworkでは、 SSHLibrary を使ってSSHのテストができます。

そこで今回、SSHLibraryを試してみました。

 
目次

 

環境

  • Python 2.7.14
    • SSHLibraryがPython3系に対応していないため
  • Robot Framework 3.0.2
  • SSHLibrary 2.1.3

 

SSHサーバの用意

SSHLibraryはSSHクライアントなので、SSHサーバを別途用意する必要があります。

今回はSSHサーバをDocker (Ubunt 16.04ベース) で作成します。

なお、Dockerfileの内容は、Dockerのドキュメントにあったものをそのまま使います。
Dockerize an SSH service | Docker Documentation

また、公開鍵認証も試すため、以下を参考にDockerfileや公開鍵を準備します。
Docker | 公開鍵を使ってサーバーにssh接続する ( コンテナに公開鍵をコピーする場合 ) - Qiita

 
まずは公開鍵を準備します。

$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_sshlibrary_sample

Dockerコンテナに公開鍵を転送するため、作成した公開鍵( id_rsa_sshlibrary_sample.pub ) を、Dockerfileと同じディレクトリに入れておきます。

 
Dockerfileは以下の通りです。

FROM ubuntu:16.04

RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:screencast' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

# ローカルで生成した公開鍵をコンテナへ転送
COPY id_rsa_sshlibrary_sample.pub /root/authorized_keys

# ディレクトリ作成、キーの移動、パーミッションの変更
CMD mkdir ~/.ssh && \
    mv ~/authorized_keys ~/.ssh/authorized_keys && \
    chmod 0600 ~/.ssh/authorized_keys

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

 
ビルド後、起動しておきます。

# ビルド
$ docker build -t eg_sshd .

# 起動:Dockerのポート22はMacの12345ポートへと転送
$ docker run -d -p 12345:22 --name test_sshd eg_sshd

 
なお、このテスト終了後は削除を忘れずに行います。

$ docker stop test_sshd
$ docker rm test_sshd
$ docker rmi eg_sshd

 

SSHLibraryの実行

インストール

pipでインストールします。

なお、以下のissueにある通り、まだPython3系では動かないことに注意します。

# バージョン確認
$ python --version
Python 2.7.14

# pipでインストール
pip install robotframework-sshlibrary

 

テストケースの作成

今回はパスワード認証と公開鍵認証の2つでSSH接続してみます。

*** Settings ***
Library  SSHLibrary

*** Variables ***
${user}  root
${password}  screencast

*** Test Cases ***
パスワードでログインしてhelloする
    Open Connection  localhost  port=12345
    Login  root  screencast
    ${output} =  Execute Command  echo Hello SSHLibrary with password!
    Log To Console  ${\n}${output}
    Should Be Equal  ${output}  Hello SSHLibrary with password!
    Close All Connections

公開鍵でログインしてhelloする
    Open Connection  localhost  port=12345
    # 鍵は秘密鍵を指定する
    Login With Public Key  root  id_rsa_sshlibrary_sample  screencast
    ${output} =  Execute Command  echo Hello SSHLibrary with public key!
    Log To Console  ${\n}${output}
    Should Be Equal  ${output}  Hello SSHLibrary with public key!
    Close All Connections

 

テストの実行

両方のテストがパスしました。

$ robot test_ssh.robot 
===========================
Test Ssh
===========================
パスワードでログインしてhelloする    ...
Hello SSHLibrary with password!
パスワードでログインしてhelloする    | PASS |
-------------------------------------
公開鍵でログインしてhelloする    ...
Hello SSHLibrary with public key!
公開鍵でログインしてhelloする    | PASS |
-------------------------------------
Test Ssh    | PASS |
2 critical tests, 2 passed, 0 failed
2 tests total, 2 passed, 0 failed

 

ソースコード

GitHubに上げました。ssh_library_sample ディレクリの中が今回のものです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

Robot FrameworkのlintツールであるRobot Framework Lintを試してみた

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

Robot Frameworkのlintツール(ソースコード静的解析ツール)を探したところ、 Robot Framework Lint がありました。
boakley/robotframework-lint: Linter for robot framework plain text files

そこで今回は Robot Framework Lintを試してみました。

 
目次

 

環境

  • Python 3.6.3
  • Robot Framework 3.0.2
  • Robot Framework Lint 0.9

Robot Framework LintのインストールはpipでOKです。

pip install --upgrade robotframework-lint

 

Lintの実行

例えば、こんな感じのテストファイル test_selenium.robot があるとします。

*** Settings ***
Library  SeleniumLibrary

*** Variables ***
${browser}  chrome

*** Keywords ***
ブラウザを起動する
    Open Browser  https://google.co.jp  ${browser}

*** Test Cases ***
Seleniumをテストする
    ブラウザを起動する
    Close Browser

 
このファイルに対してlintを実行してみます。

$ rflint test_selenium.robot 
+ test_selenium.robot
W: 2, 0: No suite documentation (RequireSuiteDocumentation)
E: 13, 0: No testcase documentation (RequireTestDocumentation)
E: 9, 0: No keyword documentation (RequireKeywordDocumentation)
W: 8, 0: Too few steps (1) in keyword (TooFewKeywordSteps)

結果が出力されました。

Documentがなかったり、テストケースの中のステップが短すぎるようです。

 

デフォルトのlint内容

rflint --list コマンドにて、デフォルトのlint内容が確認できます。

$ rflint --list
E DuplicateKeywordNames
E DuplicateTestNames
W FileTooLong
W InvalidTable
W LineTooLong
W PeriodInSuiteName
W PeriodInTestName
E RequireKeywordDocumentation
W RequireSuiteDocumentation
E RequireTestDocumentation
E TagWithSpaces
W TooFewKeywordSteps
W TooFewTestSteps
W TooManyTestCases
W TooManyTestSteps
W TrailingBlankLines

 
それぞれの内容はソースコードを見て確認します。
https://github.com/boakley/robotframework-lint/tree/master/rflint/rules

 

lintの範囲

lintの範囲を確かめるため、

  • 一つのファイル内でキーワードが重複するケース
  • 複数のファイル間でキーワードが重複するケース

を試してみます。

 
test_duplicate_in_onefile.robot

*** Settings ***
Documentation  一つのファイルで重複したテストケースを含むテスト

*** Test Cases ***
一つのファイルでテストケース名が重複
    Log To Console  foo

一つのファイルでテストケース名が重複
    Log To Console  bar

 

  • test_duplicate_in_multi_file1.robot
  • test_duplicate_in_multi_file2.robot
*** Settings ***
Documentation  複数のファイルで重複したテストケースを含むテスト

*** Test Cases ***
複数のファイルでテストケース名が重複
    Log To Console  foo

 
rflintを実行します。

$ rflint .
+ ./test_duplicate_in_multi_file1.robot
E: 6, 0: No testcase documentation (RequireTestDocumentation)
W: 5, 0: Too few steps (1) in test case (TooFewTestSteps)
+ ./test_duplicate_in_multi_file2.robot
E: 6, 0: No testcase documentation (RequireTestDocumentation)
W: 5, 0: Too few steps (1) in test case (TooFewTestSteps)
+ ./test_duplicate_in_onefile.robot
E: 8, 0: Duplicate testcase name '一つのファイルでテストケース名が重複' (DuplicateTestNames)
E: 6, 0: No testcase documentation (RequireTestDocumentation)
W: 5, 0: Too few steps (1) in test case (TooFewTestSteps)
E: 9, 0: No testcase documentation (RequireTestDocumentation)
W: 8, 0: Too few steps (1) in test case (TooFewTestSteps)

これよりlintの範囲はテストケースファイルのようです。

 

カスタムルールを作成する

Wikiによると、カスタムルールを作成できるようです。
How to write custom rules · boakley/robotframework-lint Wiki

 

カスタムルールファイルのディレクトリを確認する

カスタムルールファイルをどこに置けばよいのか確認したところ、

At the moment, rflint will only look for rules in the rules folder where rflint is installed.

Home · boakley/robotframework-lint Wiki

Custom rules should be put in the site-rules folder. The only difference between these classes is how and when they are called.

How to write custom rules · boakley/robotframework-lint Wiki

とありました。

robotframework-lint がインストールされているディレクトリの中にある rules の中に site-rules を追加すれば良さそうでした。

ディレクトリを確認すると、

$ pwd
/path/to/rfenv363/lib/python3.6/site-packages

$ tree rflint
rflint
├── __init__.py
...
├── rules
│   ├── keywordRules.py
│   ├── otherRules.py
│   ├── suiteRules.py
│   └── testcaseRules.py
...

のようです。

ただ、ディレクトリが深いので他の方法がないかを探したところ、コマンドラインオプションで指定できるようでした。

$ rflint --help
usage: python -m rflint [-h] [--error RULENAME] [--ignore RULENAME]
                        [--warning RULENAME] [--list] [--describe]
                        [--no-filenames] [--format FORMAT] [--version]
                        [--verbose] [--configure CONFIGURE] [--recursive]
                        [--rulefile RULEFILE] [--argumentfile ARGUMENTFILE]
                        ...

A style checker for robot framework plain text files.

positional arguments:
  file

optional arguments:
...
  --rulefile RULEFILE, -R RULEFILE
                        import additional rules from the given RULEFILE

なお、ディレクトリは指定できないようです。

$ rflint --rulefile rflint/rules/ .
rflint: rflint/rules/: exception while loading: [Errno 21] Is a directory: 'rflint/rules/'

 
今回はお手軽にするため、コマンドラインオプションでカスタムルールファイルを指定することとします。

 

カスタムルールファイルを作成する

Pyhonにてカスタムルールファイルを作成します。

ルールとして作成できるのは、

  • SuiteRule
  • ResourceRule
  • TestRule
  • KeywordRule
  • GeneralRule

があるようです。
How to write custom rules · boakley/robotframework-lint Wiki

 
今回は「3文字未満のキーワードはエラーとする」というカスタムキーワードルールを作成します。

# 継承元のKeywordRule、およびlintで出力するレベルをimport
from rflint.common import KeywordRule, ERROR


# KeywordRuleを継承したクラスを定義
class TooShortKeywordRule(KeywordRule):
    # クラス変数 severity に、出力レベルを指定
    severity = ERROR

    # apply()メソッドに、実際のチェック内容を指定
    def apply(self, keyword):
        # チェックエラーとする条件
        if len(keyword.name) < 3:
            # reportメソッドを使って、lintエラーになった時の内容を出力する
            # 第一引数は該当したオブジェクト、第二引数はメッセージ、第三引数は該当行
            self.report(keyword, f'too short keyword name: {keyword.name}', keyword.linenumber)

 
なお、KeywordRuleで参照できる属性は以下に書かれています。
The Keyword class · boakley/robotframework-lint Wiki

他のルールも、同様のページがWikiに用意されています。

 

lint対象のファイル

今回は以下のファイルをlint対象にします。

test_error_keyword_rule.robot

*** Settings ***
Documentation  カスタムキーワードルール違反


*** Keywords ***
ふー
    Log To Console  baz

ふーー
    Log To Console  hoo

*** Test Cases ***
一つのファイルでテストケース名が重複
    ふー

 

カスタムルールを追加したlintの実行

test_error_keyword_rule.robot ファイルに対してlintを実行してみます。

$ rflint --rulefile custom_rule/keyword_rule.py test_error_keyword_rule.robot 
+ test_error_keyword_rule.robot
E: 14, 0: No testcase documentation (RequireTestDocumentation)
W: 13, 0: Too few steps (1) in test case (TooFewTestSteps)
E: 7, 0: No keyword documentation (RequireKeywordDocumentation)
W: 6, 0: Too few steps (1) in keyword (TooFewKeywordSteps)
E: 6, 0: too short keyword name: ふー (TooShortKeywordRule)
E: 10, 0: No keyword documentation (RequireKeywordDocumentation)
W: 9, 0: Too few steps (1) in keyword (TooFewKeywordSteps)

E: 6, 0: too short keyword name: ふー (TooShortKeywordRule) が出力されています。

一方、 ふーー というキーワードは3文字なのでlintエラーの対象外となりました。

 

ソースコード

GitHubに上げました。 rflint_sample ディレクリの中が今回のものです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

Robot Framework + Libdocにて、自作ライブラリのドキュメントを作成する

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

Robot Framework Advent Calendar 2017の7日目でRobot Frameworkの自作ライブラリを作成しました。
Robot Frameworkのライブラリを自作する - メモ的な思考的な

その時は自作ライブラリにドキュメントを付けていませんでした。

今回は、Robot Frameworkに付属している Libdoc を使い、自作ライブラリのドキュメントを作成してみます。

 
目次

 

環境

  • Python 3.6.3
  • Robot Framework 3.0.2

 
なお、対象の自作ライブラリは、以下を拡張していきます。

MyLibrary.py

from robot.api import logger


class MyLibrary:
    def hello_world(self, name='foo'):
        logger.console(f'hello, world {name} !')

 

Libdocでドキュメントを生成する

Libdoc では、ソースコード中のコメントを元にドキュメントを作成します。

最初なので hello, world的にLibdocでドキュメントを生成してみます。

# ディレクトリ構成を確認する
$ tree libdoc_sample/
libdoc_sample/
└── MyLibrary.py

0 directories, 1 file

# MyLibrary.pyファイルがあるディレクトリへ移動する
$ cd libdoc_sample/

# ヘルプで実行方法を確認する
$ python -m robot.libdoc --help
robot.libdoc -- Robot Framework library documentation generator

Version:  3.0.2 (Python 3.6.3 on darwin)

Usage:  python -m robot.libdoc [options] library output_file
...

# robot.libdocを実行すると、ドキュメントのHTMLが生成される
$ python -m robot.libdoc MyLibrary.py MyLibrary.html
/path/to/libdoc_sample/MyLibrary.html

# 中身を確認する
$ open MyLibrary.html 

 
できあがったHTMLはこんな感じです。

Robot Frameworkのライブラリドキュメントでよく見かけるフォーマットです。

f:id:thinkAmi:20171217153012p:plain:w300

 
引き続き、このドキュメントに追加していきます。

 

ドキュメントのシンタックスを決める

ドキュメントを書く前に、ドキュメントのシンタックスを決めておきます。

ユーザガイドによると、以下のシンタックスが利用できます。
5.1.3 Documentation syntax - Robot Framework User Guide

  • Robot Framework documentation syntax
  • HTML documentation syntax
  • Plain text documentation syntax
  • reStructuredText documentation syntax

 
なお、Robot Framework documentation syntax以外にする場合、 ROBOT_LIBRARY_DOC_FORMAT に使用するシンタックスを設定する必要があります。

今回はデフォルトの Robot Framework documentation syntax とします。

 

Introductionを記述

デフォルトでは

Documentation for test library <ライブラリ名>

となっている部分を記述します。

Pythonのクラスコメントを追加し、ドキュメントを生成します。

class MyLibrary:
    """マイライブラリ"""
    def hello_world(self, name='foo'):
        logger.console(f'hello, world {name} !')

 
生成されたものを見ると、Introductionが差し替わっていました。

f:id:thinkAmi:20171217153635p:plain:w150

 

キーワードのドキュメントを追加

ソースコード中のメソッドにコメントを追加します。

class MyLibrary:
    """マイライブラリ"""

    def hello_world(self, name='foo'):
        """ハローワールドを出力します"""
        logger.console(f'hello, world {name} !')

 
生成されたものを見ると、キーワードのドキュメントが追加されていました。

f:id:thinkAmi:20171217154044p:plain

 

Library scopeの変更

Library scopeの設定を変更することで、自動的に変更されます。

class MyLibrary:
    """マイライブラリ"""

    # Library scopeの設定を変更
    ROBOT_LIBRARY_SCOPE = 'TEST SUITE'

 
生成されたものです。

f:id:thinkAmi:20171217154650p:plain:w200

 

BoldやItalicでの文字装飾

コメント中に

  • Bold: *<文字列>*
  • Italic: _<文字列>_

と書くことで修飾できます。

class MyLibrary:
    """マイライブラリ

    *太字です*
    _イタリックです_
    普通です
    """
#...

 
生成されたものです。

f:id:thinkAmi:20171217155617p:plain:w250

 
なお、複数行の太字はうまくいきませんでした。

 

リスト表示

Markdownと同じように、 ハイフン - を先頭に付けることでリスト表示されます。

なお、リストのネストはなさそうです。

class MyLibrary:
    """マイライブラリ

    *太字です*
    _イタリックです_
    普通です

    - リスト1
    - リスト2
    """

 
生成されたものです。

f:id:thinkAmi:20171217172156p:plain:w250

 

URLのリンク

URLのリンクは以下の2種類となります。

  • https://google.co.jp のようなURLを書く
  • [https:/google.co.jp|Googleへ] のような記法にする

 
両者の違いを実際に見てみます。

class MyLibrary:
    """マイライブラリ

    *太字です*
    _イタリックです_
    普通です

    - リスト1
    - リスト2

    Googleへ https://google.co.jp
    こちらも [https://google.co.jp|Googleへ]
    """

 
生成されたものです。

f:id:thinkAmi:20171217172607p:plain:w300

 

キーワードへの内部リンク

バックスラッシュ (`) を使うことで、キーワードへのリンクとなります。

 

class MyLibrary:
    """マイライブラリ

    *太字です*
    _イタリックです_
    普通です

    - リスト1
    - リスト2

    Googleへ https://google.co.jp
    こちらも [https://google.co.jp|Googleへ]
    
    `Hello World` へ
    """

 
生成されたものです。

Introductionの Hello World をクリックすると、Keywordsの Hello World へとジャンプします。

クリックすると、このように青字でKeywordsがハイライトされます。

f:id:thinkAmi:20171217173046p:plain:w250

 

インラインコードスタイル

Markdownだとシングルバッククォート(`) で書きますが、Robot Frameworkではダブルバッククォート(``)で書きます。

class MyLibrary:
    """マイライブラリ

    *太字です*
    _イタリックです_
    普通です

    - リスト1
    - リスト2

    Googleへ https://google.co.jp
    こちらも [https://google.co.jp|Googleへ]

    `Hello World` へ

    ``インラインコードスタイル``

 
生成されたものです。

f:id:thinkAmi:20171217174108p:plain:w200

 

セクションへの自動リンク

セクション

  • Introduction
  • Importing
  • Shortcuts
  • Keywords

については、各単語をシングルバッククォートで囲むことで、自動的に内部リンクが作成されます。

class MyLibrary:
    """マイライブラリ

    セクションへのリンク

    - `introduction`
    - `importing`
    - `shortcuts`
    - `keywords`

 
生成されたものです。

f:id:thinkAmi:20171217174732p:plain:w250

 

カスタムセクションの作成とカスタムセクションへの内部リンク

カスタムセクションは、 = <セクション名> = で作成できます。

また、シングルバッククォートでセクション名を囲むことで、カスタムセクションへの内部リンクが作成されます。

class MyLibrary:
    """マイライブラリ

    = カスタムセクション =

    ここがカスタムセクション

    = 次のセクション =

    `カスタムセクション` へのリンク

 
生成されたものです。

f:id:thinkAmi:20171217175222p:plain:w250

 

表は以下で生成できます。

  • | で区切ると、1列追加
    • | と項目の間には半角スペース が必要
  • 列のタイトルは、 = で囲む
  • 空白セルは、| の間に半角スペースを入れる (| |)
class MyLibrary:
    """マイライブラリ

    | =タイトル= | =もう一つタイトル= |
    | 1行1列目 | 1行2列目 |
    | | 1列目が空白 |
    | 2列目が空白 | |

 
生成されたものです。

f:id:thinkAmi:20171217180012p:plain:w250

 

キーワードの引数表示について

Pythonの引数には

  • 引数なし
  • デフォルト値なしの引数
  • デフォルト値ありの引数
  • *args
  • **kwargs

があるため、それぞれを表示してみます。

class MyLibrary:
#...
    def no_args(self):
        pass
    
    def multi_args(self, one, two='2', *args, **kwargs):
        pass

 
生成されたものです。

f:id:thinkAmi:20171217180526p:plain

 
ざっと書きましたが、これで公式ドキュメントにあるようなライブラリのドキュメントが作れそうです。

 

ソースコード

GitHubに上げました。libdoc_sample ディレクリの中が今回のものです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

Mac + IntelliJ IDEA + Python pluginにおける、pycharm-debug.egg のありかについて

IntelliJ IDEA + Python pluginでリモートデバッグをする際、

  • pycharm-debug.egg
  • pycharm-debug-py3k.egg

が必要です。

ただ、どこにあるか分からなかったため、調べた時のメモを残します。

 

環境

 

ありか

PyCharmでは

  • /Applications/PyCharm.app/pycharm-debug.egg
  • /Applications/PyCharm.app/Contents/debug-eggs/pycharm-debug.egg

などにあったようです。
Where is the pycharm-debug.egg archive on mac found? - Stack Overflow

ただ、手元のIntelliJ IDEA + Python pluginでは見当たりませんでした。

 
そこで調べてみたところ、IntelliJ IDEAのヘルプに記載がありました。
Remote Debugging - Help | IntelliJ IDEA

~/Library/Application Support/IntelliJIDEAXXXX.X/python/ のようです。

 
findコマンドでも探してみます。

$ pwd
~/Library/Application Support

$ find . -name 'pycharm-*.egg'
./IntelliJIdea2016.2/python/pycharm-debug-py3k.egg
./IntelliJIdea2016.2/python/pycharm-debug.egg
./IntelliJIdea2016.3/python/pycharm-debug-py3k.egg
./IntelliJIdea2016.3/python/pycharm-debug.egg
./IntelliJIdea2017.1/python/pycharm-debug-py3k.egg
./IntelliJIdea2017.1/python/pycharm-debug.egg
./IntelliJIdea2017.2/python/pycharm-debug-py3k.egg
./IntelliJIdea2017.2/python/pycharm-debug.egg
./IntelliJIdea2017.3/python/pycharm-debug-py3k.egg
./IntelliJIdea2017.3/python/pycharm-debug.egg

 
手元にあるものだと、バージョン 2016.2 からこの場所にあるようです。

Robot FrameworkのキーワードEvaluateでPythonのコードを実行する

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

Robot Frameworkの組込キーワード Evaluate を使うとPythonコードを実行できます。

 
今回は Evaluate キーワードを試してみます。

 
目次

 

環境

 

文字列のフォーマット

Robot Framework単独では難しいのが文字列のフォーマットです。

一方、Pythonで書くと楽です。

今回は

  • %演算子
  • str.format()関数
  • f-strings
    • Python3.6以上

を試します。

Robotframework-DebugLibraryの rfdebug コマンドでREPLを起動し、それぞれを確認してみます。

$ rfdebug
====================
Robot Debug9 R36Le9
====================
RFDEBUG REPL
>>>>> Enter interactive shell
Only accepted plain text format keyword seperated with two or more spaces.
Type "help" for more information.
> ${結果} =  Evaluate  '%06d %s' % (1, 'ゼロ埋めです')
# ${結果} = '000001 ゼロ埋めです'
> ${結果} =  Evaluate  'foo {}'.format('bar')
# ${結果} = 'foo bar'
> ${結果2} =  Evaluate  'foo {}'.format('bar')
# ${結果2} = 'foo bar'
> ${結果3} =  Evaluate  f'baz ${結果2}'
# ${結果3} = 'baz foo bar'

 
いずれも動作しました。

 

Pythonクラスのインスタンスを取得する

Evaluateのソースコードを読むと、内部ではPythoneval() 関数を使っています。
https://github.com/robotframework/robotframework/blob/3.0.2/src/robot/libraries/BuiltIn.py#L2963

また、Evaluateの引数のmoduleやnamespaceは __import__() 関数でimportされています。
https://github.com/robotframework/robotframework/blob/3.0.2/src/robot/libraries/BuiltIn.py#L2997

そのため、Pythonクラスのインスタンスを取得できそうです。

 

Robot FrameworkのLibraryで対象モジュールをimport済の場合
sys.modulesを使う

例えば、

*** Settings ***
Library  SeleniumLibrary
Library  DebugLibrary

*** TestCases ***
読み込み済モジュールに含まれるクラスをインスタンス化する
    Debug

とした時に、

  • SeleniumLibraryをimport済
  • Headless Firefoxの設定を行うために selenium.webdriver.firefox.options.Option クラスのインスタンスを取得したい

とします。

 
この場合、 sys.modulesselenium パッケージが追加されています。

 
そのため、

${options} =  Evaluate  sys.modules['selenium.webdriver.firefox.options'].Options()  sys

としてOptionsクラスのインスタンスを取得できます。

なお、引数は

  • 第1引数
    • sys.modulesselenium.webdriver.firefox.options にある Options クラスをインスタンス化する処理
  • 第2引数
    • 第1引数で使われているモジュールのうち、追加でimportが必要なモジュール名
      • 今回は sys モジュールを使用

です。

 
本当に取得できたのか、REPLで確認してみます。

# 上記例が含まれるRobot Frameworkのテストケースを実行
$ robot test_get_instance_from_already_imported_module.robot 
...

# キーワードDebugに到達したため、REPLが起動
>>>>> Enter interactive shell
Only accepted plain text format keyword seperated with two or more spaces.
Type "help" for more information.

# Robot Frameworkライブラリの確認:SeleniumLibraryあり
> libs
< Imported libraries:
   BuiltIn 3.0.2
       An always available standard library with often needed keywords.
   DebugLibrary 1.0.2
       Debug Library for RobotFramework
   Easter 
   Reserved 
   SeleniumLibrary 3.0.1
       SeleniumLibrary is a web testing library for Robot Framework.
< Bultin libraries:
   BuiltIn 
   Collections 
   DateTime 
   Dialogs 
   Easter 
   OperatingSystem 
   Process 
   Remote 
   Reserved 
   Screenshot 
   String 
   Telnet 
   XML 

# sys.modulesにあるか確認:あった
> Evaluate  sys.modules['selenium.webdriver.firefox.options']  sys
< <module 'selenium.webdriver.firefox.options' from '/path/to/rfenv363/lib/python3.6/site-packages/selenium/webdriver/firefox/options.py'>

# 上記のコードを試す:インスタンスを取得できた
> ${options} =  Evaluate  sys.modules['selenium.webdriver.firefox.options'].Options()  sys
# ${options} = <selenium.webdriver.firefox.options.Options object at 0x10eee60b8>

   

Robot Frameworkを対象モジュールをimportしていない場合

例えば、

*** Settings ***
Library  DebugLibrary

*** TestCases ***
読み込まれていないモジュールに含まれるクラスをインスタンス化する
    Debug

とした時に、

とします。

 

sys.modulesを使う場合

sys.modulesを使う場合は、Libraryでimportした時と同じです。

# 上記のテストケースを実行
$ robot test_get_instance_from_no_import_module.robot 
...

# キーワードDebugに到達したため、REPLが起動
>>>>> Enter interactive shell
Only accepted plain text format keyword seperated with two or more spaces.
Type "help" for more information.

# sysとdistutils.versionをimportして、LooseVersionクラスのインスタンスを取得
> Evaluate  sys.modules['distutils.version'].LooseVersion('3.0.2')  sys,distutils.version
< LooseVersion ('3.0.2')

 

__import__()関数を使う場合

Pythonでのimport同様、 __import__() 関数も使えます。
__import__ - 2. 組み込み関数 — Python 3.6.3 ドキュメント

ただ、

name 変数が package.module 形式であるとき、通常は、name で指名されたモジュール ではなく、最上位のパッケージ (最初のドットまでの名前) が返されます。しかしながら、空でない fromlist 引数が与えられると、 name で指名されたモジュールが返されます。

__import__ - 2. 組み込み関数 — Python 3.6.3 ドキュメント

のため、第1引数だけ指定すると

$ robot test_get_instance_from_no_import_module.robot 
...
> Evaluate  __import__('distutils.version').LooseVersion('3.0.2')
! keyword: Evaluate  __import__('distutils.version').LooseVersion('3.0.2')
! Evaluating expression '__import__('distutils.version').LooseVersion('3.0.2')' failed: AttributeError: module 'distutils' has no attribute 'LooseVersion'

と、エラーになります。

そのため、 fromlist 引数も使用します。

$ robot test_get_instance_from_no_import_module.robot 
...
> Evaluate  __import__('distutils.version', fromlist=['LooseVersion']).LooseVersion('3.0.2')
< LooseVersion ('3.0.2')

 

importlib.import_module()を使う場合

__import__() 関数の説明の中で

__import__() を直接使用することも推奨されず、 importlib.import_module() の方が好まれます。

__import__ - 2. 組み込み関数 — Python 3.6.3 ドキュメント

とあったため、 importlib.import_module() を見てみます。

 
importlib.import_module()の説明には

import_module() 関数は importlib.__import__() を単純化するラッパーとして働きます。つまり、この関数のすべての意味は importlib.__import__() から受け継いでいます。これらの2つの関数の最も重要な違いは、 import_module() が指定されたパッケージやモジュール (例えば pkg.mod) を返すのに対し、 __import__() はトップレベルのパッケージやモジュール (例えば pkg) を返すことです。

importlib.import_module(name, package=None) - 31.5. importlib — import の実装 — Python 3.6.3 ドキュメント

とありました。

試してみます。

$ robot test_get_instance_from_no_import_module.robot 
...
> Evaluate  importlib.import_module('distutils.version').LooseVersion('3.0.2')  importlib
< LooseVersion ('3.0.2')

同じ結果になりました。

個人的には __import__() よりも importlib.import_module() の方が分かりやすいです。

 

ソースコード

GitHubに上げました。builtin_library_samples/evaluate ディレクリの中が今回のものです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

DebugLibraryを使って、Robot Framework のREPLやテスト実行中のREPLを試す

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

プログラム言語で何かをちょっと試したいという時は、REPL (Read-eval-print loop) が便利です。

Robot FrameworkでもREPLがないかを探したところ、Robotframework-DebugLibraryを使えば良さそうでした。
https://github.com/xyb/robotframework-debuglibrary

そこで今回は、Robotframework-DebugLibraryを使って、Robot Framework のREPLを試してみます。

 
目次

 

環境

  • Python 3.6.3
  • Robot Framework 3.0.2
  • Robotframework-DebugLibrary 1.0.2

Robotframework-DebugLibraryのインストールは pip install robotframework-debuglibrary でOKです。

 

コンソールでREPLを試す

起動

コンソールを起動し、 rfdebug コマンドを入力すると、REPLが起動します。

$ rfdebug
=========================
Robot Debugqqpsyuvs
=========================
RFDEBUG REPL
>>>>> Enter interactive shell
Only accepted plain text format keyword seperated with two or more spaces.
Type "help" for more information.
> 

 

コンソール出力

コンソール出力してみます。

> Log To Console  ハローワールド
ハローワールド

 

変数を使う

変数を使ってみます。

> ${ham} =  Set Variable  spam
# ${ham} = 'spam'
> Log To Console  ${ham}
spam

 

入力履歴

履歴も残っているようで、同じコマンドを打つと、前回のものが表示されます。

f:id:thinkAmi:20171216074446p:plain

 
右矢印キーを押すと、補完されます。

f:id:thinkAmi:20171216080823p:plain

 

入力補完

ある程度入力し、 Tab キーを押すと、入力候補が表示されます。

f:id:thinkAmi:20171216074745p:plain

 

インポートされているライブラリの確認

インポートされているライブラリを見てみます。 libs (もしくは l ) で表示されます。

> libs
< Imported libraries:
   BuiltIn 3.0.2
       An always available standard library with often needed keywords.
   DebugLibrary 1.0.2
       Debug Library for RobotFramework
   Easter 
   Reserved 
< Bultin libraries:
   BuiltIn 
   Collections 
   DateTime 
   Dialogs 
   Easter 
   OperatingSystem 
   Process 
   Remote 
   Reserved 
   Screenshot 
   String 
   Telnet 
   XML 

 

ヘルプの表示

どんなコマンドが用意されているかヘルプを表示してみます。

> help
Input Robotframework keywords, or commands listed below.
Use "libs" or "l" to see available libraries,
use "keywords" or "k" see list of library keywords,
use the TAB keyboard key to auto complete keywords.

Documented commands (type help <topic>):
========================================
EOF  exit  help  k  keywords  l  libs  pdb  s  selenium

 
Seleniumがあるみたいです。さらにヘルプを表示してみます。

> help selenium
Start a selenium 2 webdriver and open url in browser you expect.

        s(elenium)  [<url>]  [<browser>]

        default url is google.com, default browser is firefox.

 
そういえば、SeleniumLibraryをインストール済でした。

(rfenv363) $ pip list
...
robotframework-seleniumlibrary (3.0.1)

 
そこで、Seleniumを使ってみます。

> selenium
# import library  Selenium2Library
! keyword: import library  Selenium2Library
! Importing test library 'Selenium2Library' failed: ModuleNotFoundError: No module named 'Selenium2Library'
Traceback (most recent call last):
  None
PYTHONPATH:
  /path/to/rfenv363/bin
...
  /path/to/rfenv363/lib/python3.6/site-packages
# open browser  http://www.google.com/  firefox
! keyword: open browser  http://www.google.com/  firefox
! No keyword with name 'open browser' found.

Selenium2Libraryをインストールしていないので、起動に失敗したようです。 手元のSeleniumLibraryではダメなようですね。

 

REPLの終了

Ctrl + D にて終了します。

> (Ctrl + D を入力)

>>>>> Exit shell.
RFDEBUG REPL    | PASS |
----------------------------
Robot Debug Xgd1T H    | PASS |
1 critical test, 1 passed, 0 failed
1 test total, 1 passed, 0 failed
====================
Output:  None

 

Robot Frameworkのテストを実行中に、REPLを試す

Robot Framworkのテストを実行中に、REPLを使ってデバッグしたいことがあるかもしれません。

テストケース中にて Debug キーワードを使うことで、その場所の状態でREPLが起動します。

以下のテストケースで試してみます。

*** Settings ***
Library  DebugLibrary
Library  SeleniumLibrary

*** Keywords ***
say
    Log To Console  hello, world

ハロー
    Log To Console  はろー

testハロー
    Log To Console  testです

*** Test Cases ***
何かテストする
    Log To Console  hello
    ハロー
    ${ham} =  Set Variable  変数です
    
    # この時点の状態で、REPLが起動する
    Debug

    ${spam} =  Set Variable  書き換え可能です

 

REPLの起動

テストを実行すると、 Debug キーワードがあるところで自動的に停止します。

$ robot test_debug_library.robot 
===========================
Test Debug Library
===========================
何かテストする    hello
.はろー
..
>>>>> Enter interactive shell
Only accepted plain text format keyword seperated with two or more spaces.
Type "help" for more information.
> 

 

キーワードを使ってみる

さきほどのREPLと同じです。

> Log To Console  こんにちは
こんにちは

 

変数の中身を確認する

ためしに変数名を入力してみます。

> ${ham}
! keyword: ${ham}
! FAILED: TypeError("run_keyword() missing 1 required positional argument: 'name'",)

 
キーワードを入力しないといけないみたいですね。

> Log To Console  ${ham}
変数です

テスト中の変数の中身が出ました。

 

変数の中身を書きかえる

テストケース中の変数も書きかえられます。

> ${ham} =  Set Variable  書きかえました
# ${ham} = '書きかえました'
> 

 
REPLを抜けると変数が書きかわっています。

>>>>> Exit shell.
.書きかえました

 
参考:書きかえない場合

>>>>> Exit shell.
.変数です

 

ユーザ定義のキーワードを使う

Keywordssay キーワードを定義していたので使ってみます。

> say
hello, world

動きました。

日本語キーワードも問題ないです。

> ハロー
はろー

> testハロー
testです

 

importされているライブラリのキーワード使用

importされているライブラリのキーワードも使用できます。

今回はSeleniumLibraryをimportしているので、 Open Browser https://google.co.jp chrome とするとChromeが起動します。

> Open Browser  https://google.co.jp  chrome
< 1

 

入力補完

入力補完も可能です。

このテストケースではSeleniumLibraryをimportしているため、その分も候補に表示されます。

f:id:thinkAmi:20171216083740p:plain

 
なお、入力候補間の移動は

  • 進む : Tab
  • 戻る : Shift + Tab

です。

 

REPLの終了

Ctrl + D で終了します。

exit でも大丈夫なようです。

> help exit
Exit the interpreter. You can also use the Ctrl-D shortcut.

 
REPLを終了すると、テストが続きから実行されます。

> (Ctrl + Dを入力)

>>>>> Exit shell.
.変数です
何かテストする    | PASS |
--------------------
Test Debug Library    | PASS |
1 critical test, 1 passed, 0 failed
1 test total, 1 passed, 0 failed

 
テストケース中でいろいろとできるのは便利ですね。