コンテンツにスキップ

テストスクリプト作成のプラクティス

Note

スクリプトが実行されるカレントディレクトリは、指定された Python ファイルと同じディレクトリになります。 スクリプト内で相対パスを使用する際はご注意ください。

テストスクリプトの実行結果

ScriptGenerator で生成したコードを実行した結果の見え方について記載します。

テストスクリプト成功

TestRunner 実行結果

TestRunnerCLI 実行結果

成功時には、”テストスクリプトの実行が完了しました。” と表示されます。 別途メッセージを表示させたい場合は、テストスクリプトを編集する必要があります。こちらを参照してください。

テストスクリプト失敗

TestRunner 実行結果

TestRunnerCLI 実行結果

失敗時には、”スクリプトが正常終了しませんでした。” と表示されます。

CLI 実行時の結果の詳細は別途ソフトウェアマニュアル内の TestRunnerCLI マニュアル > 結果を確認する を参照してください。

結果の集計

テストスクリプトのテスト結果は、csv 形式で一覧が表示されます。詳細は別途ソフトウェアマニュアル内の TestRunnerCLI マニュアル > レポート構成 を参照してください。

テスト結果ではテストスクリプト毎に結果を表示しますが、テストスクリプト内で別途メッセージを表示可能です。こちらを参照してください。

記載したメッセージの内容は OutputLog.log に記載されます。OutputLog.log を読み込み、結果を集計可能です。

例 : Python を使用し結果を集計する

# OutputLog.log のフルパスを記載し読み込みます。
f = open(r'xx\xx\OutputLog.log', 'r', encoding='UTF-8')

test_count = 0
pass_count = 0
fail_count = 0
invalid_count = 0

# 読み込んだ log を一行ずつ確認していきます。
datalist = f.readlines()
for data in datalist:
  # 今回の例では TestCaseResult:”結果” の形式でメッセージを表示させます。
  if "TestCaseResult" in data :
    test_count += 1
    # 結果が Pass と表示した場合を集計します。
    if "Pass" in data :
      pass_count += 1
    # 結果が Fail と表示した場合を集計します。
    elif "Fail" in data :
      fail_count += 1
    # Pass/Fail 以外の場合を無効として集計します。
    else :
      invalid_count += 1

print(f"テスト数:{test_count}")
print(f"Pass数:{pass_count}")
print(f"Fail数:{fail_count}")
print(f"無効数:{invalid_count}")

f.close()

テストシナリオ作成のプラクティス

テストシナリオの粒度

TestRunnerCLI でテスト実行時は、1 テストスクリプト (1Python ファイル) 毎に Pass/Failed を出力します。1 テストテーブル毎に 1 回の判定となるテストケースの作成を推奨しています。 1 つのテストスクリプト内で Fail となっていてもテストスクリプトを最後まで行いたい場合は、生成したテストスクリプトを編集する必要があります。こちらを参照してください。

テストシナリオの共通化

テスト実施する中での共通部分をまとめることで、テストの効率化が行なえます。テスト開始前の初期化処理やテスト終了後の終了処理などが該当します。 共通化を行うことで以下のようなメリットがあります。

  • 変更時に変更範囲を少なく済ませられる。 初期化などの処理に変更が入った場合に共通化を行っていないと、修正範囲が大きくなり変更量も増えてしまいます。 また、派生開発などで流用時にもテストスクリプトの変更量を抑えることができます。
  • テストスクリプトの処理が理解しやすくなる。 テストスクリプトで実施したい処理が明確になります。

例 :

**[📂](https://lets-emoji.com/open-file-folder-emoji/)**TestScenario
   **[📂](https://lets-emoji.com/open-file-folder-emoji/)**InitialSheet1
    📃initial_settings.py
   **[📂](https://lets-emoji.com/open-file-folder-emoji/)**EndSheet2
    📃end_settings.py
   **[📂](https://lets-emoji.com/open-file-folder-emoji/)**TestSheet1
    📃test_case1.py
   **[📂](https://lets-emoji.com/open-file-folder-emoji/)**TestSheet2
    📃test_case2.py
    📃test_case3.py

共通処理として作成したスクリプトを複数箇所で実行するために、別途 Python ファイルを作成する必要があります。

こちらを参照ください。

テストスクリプトファイル編集のプラクティス

実施目的別にテストスクリプトを編集した例を記載します。例では RPi-GP10 を使用したテストスクリプトを記載します。

AUTOmeal の PythonAPI はスクリプトリファレンスを参照してください。

テスト実行中に計測 ch の状態に応じて処理を変更したい

Python の “if” 文を使用して処理を分岐できます。

import automeal as am

# 計測 ch1 が Hi/Lo か判定し処理を行います。
**if** am.read_logic_rpigp10("Board1", 1) == True **:**
    # 計測 ch1 が Hi の場合の処理です。制御 ch1 を Lo に変更する。
    am.write_logic_rpigp10("Board1", 1, False)
**else :**
    # 計測 ch1 が Lo の場合の処理です。制御 ch2 を Lo に変更する。
    am.write_logic_rpigp10("Board1", 2, False)

制御処理を複数回繰り返したい

Python の “for” 文を使用して処理を繰り返し行います。

import automeal as am
import time

# 処理を 5 回繰り返します。
**for i in range(5):**
    # 制御 ch1 の Hi/Lo を交互に行います。
    am.write_logic_rpigp10("Board1", 1, True)
    # 待機を行います。 sleep(秒) で指定します。
    time.sleep(0.5)
    am.write_logic_rpigp10("Board1", 1, False)
    time.sleep(0.5)

テスト実行中にメッセージを出力したい

“print” で任意のメッセージを表示できます。

“flush = True” を使用すると、print 実行と同時にコンソールまたは [テストログ] ペインに表示されます。

上記を省略した場合、スクリプト終了時にまとめて表示されます。

import automeal as am

# ロジック 1ch の Hi/Lo を表示させる。
**print**(am.read_logic_rpigp10("Board1", 1) , **flush = True**)
# 追加のメッセージを 表示させる。
**print**("TestCase1:Pass" , **flush = True**)

ch の状態が Lo になるまで待機したい

Python の “while” 文と “sleep” を使用して待機を行うことができます。

import automeal as am
import time

# 1 秒ごとに計測 ch1 が Hi かを確認し、Hi の間は待機する。
**while** am.read_logic_rpigp10("Board1", 1) == True **:
    time.sleep(1)**

# 制御 ch2 を Hi にします。
am.write_logic_rpigp10("Board1", 2, True)

1 テストスクリプト内で Fail となった場合でも終了せず最後まで行いたい

Python の例外処理である “try” と “except” を使用することで実施できます。

import automeal as am

**try :**
    # 計測 ch1 が Hi かを検証します。
    assert am.read_logic_rpigp10("Board1", 1) == True
**except :**
    # 検証で Fail(計測 ch1 が Lo)だった場合に行う処理です。
    print("xxxTest1 : Fail" , flush = True)

**try :**
    # 計測 ch2 が Lo かを検証します。
    assert am.read_logic_rpigp10("Board1", 2) == False
**except :**
    # 検証で Fail(計測 ch2 が Lo)だった場合に行う処理です。
    print("xxxTest2 : Fail" , flush = True)

# ch1.ch2 が両方とも Hi だった場合に行う処理です。
print("xxxTest : Pass" , flush = True)

共通処理のテストスクリプト複数回実行したい

“from フォルダ名 import ファイル名” で他のテストスクリプトを使用できるようにします。 実際の使用時には ”ファイル名.関数名” で実行します。 実行するテストスクリプトは “def” で関数化する必要があります。

フォルダ構成
**[📂](https://lets-emoji.com/open-file-folder-emoji/)**TestScenario
   📃execute_test.py
   **[📂](https://lets-emoji.com/open-file-folder-emoji/)**CommonSheet
    📃initial_settings.py
   **[📂](https://lets-emoji.com/open-file-folder-emoji/)**TestCaseSheet
    📃test_case1.py
    📃test_case2.py

例 : execute_test.py

from CommonSheet import initial_settings
from TestCaseSheet import test_case1
from TestCaseSheet import test_case2

# initial_Settings.py の Init() を実行する。
initial_settings.init()
# test_Case1.py の test1() を実行する。
test_case1.test1()

# initial_settings.py の Init() を実行する。
initial_settings.init()
# test_case2.py の Test2() を実行する。
test_case2.test2()

initial_settings.py

import time
import automeal as am

# 制御 1-6ch を Hi にする。
def init() :
    print("initialize:start" , flush = True)
    am.write_logic_rpigp10("Board1", 1, True)
    am.write_logic_rpigp10("Board1", 2, True)
    am.write_logic_rpigp10("Board1", 3, True)
    am.write_logic_rpigp10("Board1", 4, True)
    am.write_logic_rpigp10("Board1", 5, True)
    am.write_logic_rpigp10("Board1", 6, True)
    time.sleep(0.5)
    print("initialize:end" , flush = True)      

test_case1.py

import time
import automeal as am

def test1() :
    # 制御 ch1 の Hi/Lo を交互に行います。
    print("test1:start" , flush = True)
    am.write_logic_rpigp10("Board1", 1, False)
    time.sleep(0.5)
    am.write_logic_rpigp10("Board1", 1, True)
    time.sleep(0.5)

    # 計測 ch1 が Hi かを検証します。
    assert am.read_logic_rpigp10("Board1", 1) == True
    print("test1:end" , flush = True)

test_case2.py

import time
import automeal as am

def test2() :
    # 制御 ch2 の Hi/Lo を交互に行います。
    print("test2:start" , flush = True)
    am.write_logic_rpigp10("Board1", 2, False)
    time.sleep(0.5)
    am.write_logic_rpigp10("Board1", 2, True)
    time.sleep(0.5)

    # 計測 ch2 が Hi かを検証します。
    assert am.read_logic_rpigp10("Board1", 2) == True
    print("test2:end" , flush = True)

複数のテストスクリプトを並列処理したい

“threading” を使用し並列処理を行います。 ”threading.Thread” を継承したクラスを作成し、”start()” 関数を使用することでスレッドを開始します。

import threading
from TestCaseSheet import test_case1
from TestCaseSheet import test_case2
import time

# 並列処理したい処理
class Test1Thread(threading.Thread):
    finish = False

    def run(self):
        while not self.finish:
            test_case1.test1()
            time.sleep(0.5)

    def stop(self):
        self.finish = True

test1 = Test1Thread()
test1.start()
for i in range(100):
    testcase2.test2()
    time.sleep(0.5)
test1.stop()

シリアルで特定の byte の値で分岐したい

Python の “if” 文を使用して処理を分岐できます。

また、get_latest_serial() は byte 配列を返すため対象の byte-1 を指定することで比較できます。

import automeal as am

# Port2 の最新の受信データを取得します。
**rcv_data = am.get_latest_serial("Port2","R")**
# Port2 の最新の受信データの 10 byte 目 が "0x0A" かを判定します。
**if rcv_data[9]** == "0x0A":
    print("True:", flush=True)
else :
    print("False:", flush=True)