こんにちは。おすしです。

■前回記事

今回はTestRailとmablの自動テストを連携したお話です。
連携方法やテストコードは下の方で全部公開しています。
※今回はmablのJenkinsプラグイン以外を使用していません。mablには便利なCLIがあるので、一度目を通しておくことをお勧めします。
自分の環境に合ったより良い連携方法をひらめくかもしれません。

mabl CLIの概要
https://help.mabl.com/docs/mabl-cli%E3%81%AE%E6%A6%82%E8%A6%81

連携図

自動化した内容

  1. Jenkinsからmablにテスト実行指令を出す。
  2. テストが完了すると、JenkinsのログからTestRailにテスト結果を記入する。
  3. 失敗したテストはGithubにissueを作成する。
  4. 失敗したテストはTestRailの結果に失敗時のスクリーンショットを添付し、「欠陥」にissueへのリンクを設定する。

連携手順①GithubとTestRailの設定

こちらの手順は前回の記事をご覧ください。

TestRailと自動テストの連携#1 Selenium/Python編
https://sqripts.com/2022/06/21/20407/

連携手順②mablの設定

APIキーを作成する

  1. メニューバーの「Setting(ワークスペース)」を押す
  2. APIS(API)」を押す
  3. API keys(APIキー)」を作成します※
  4. キーをコピーしておきます(Jenkinsの設定で使用します)

※ワークスペースの所有者レベルのユーザーのみがAPIキーを作成できます。使用しているアカウントに権限がなく、ワークスペースに使用できるAPI keyがない場合は、所有者に連絡をしてください。

mablでテストを作成する

こちらのページを使用させていただきました。

まずは、mablのレコーディング機能を利用してテストをいくつか作成しておきます。
期待結果を編集して失敗するテストも準備します。
今回のJenkinsのログからテスト結果を取得する連携では、mablテスト名を利用して結果の記入処理を行います。
そのため、各テストは重複しない一意の名称にする必要があります。

連携手順③TestRailにインポートするテストデータを作成する

mablで作成したテストをTestRailにインポートするためのCSVファイルを作成します。

例:

NoABCresultobjectivestestID
1111正三角形正三角形のテスト113562
210105二等辺三角形二等辺三角形のテスト(ABが等しい)13563
310510失敗するテスト失敗する三角形のテスト13564
4111正三角形正三角形のテスト213565
5111正三角形正三角形のテスト313566
6111正三角形正三角形のテスト413567

各カラムの内容は

  • No:テスト番号
  • A,B,C:各辺に入れる値。
  • result:「表示」ボタンを押した後の期待結果
  • objectives:テストの目的。ここをmablのテスト名と完全に一致させます。
  • testID:TestRailのテストID。インポート後に記入します

このCSVファイルをTestRailにインポートしてテストを作成します。
インポート後、CSVファイルの「testID」にテストIDを記入します。

連携手順④Jenkinsの設定

※インストールとユーザの作成までは、ほかのサイトを参考にしてください。

JenkinsにPythonのPATHを設定する

  1. サイドメニューの「Jenkinsの管理」を押します
  2. 「システムの設定」を押します
  3. 「グローバルプロパティ」のリストの「環境変数」を押します
  4. PCにインストールされているPythonのパスを設定します

mablのAPIキーを設定する

「mablの設定」で作成したAPI keyを利用します

  1. サイドメニューの「Jenkinsの管理」を押します
  2. 「Manage Credentials」を押します
  3. 「Stores scoped to Jenkins」のリストの「Domains」にある「(global)」を押します
  4. サイドメニューの「認証情報の追加」を押します
  5. 「種類」のプルダウンから「Seacret text」を選択し、以下の内容を入力します
    (1) スコープ:グローバル
    (2) Seacret:mablのAPI keyを入力
    (3) ID:わかりやすいIDをつけておきます 例:mabl_API_key など
    (4) 説明:使用目的がわかる説明を入れます
  6. 「保存」を押します

連携手順⑤コードの実装

プロジェクトの構成

こちらがプロジェクトの構成です。上から順番に説明していきます。

Data/test_data.csv

連携手順③で作成したCSVファイルです。

Module/config.py

TestRailとGithubの接続に必要なトークンやログイン情報を記載します。
Jenkinsのジョブフォルダのパスはジョブ作成後に入力します。

# Githubの設定

token_github = "Githubのトークンを入れます"

base_url_github = "GithubのレポジトリのURLを入れます"

# TestRAilの設定

user_testrail = "TestRailのユーザーIDを入れます"

password_testrail = "TestRailのパスワードを入れます"

base_url_testrail = "TestRailのURLを入れます(index.php?の前の部分まで)"

# Jenkinsのジョブフォルダのパスの例

jenkins_folder = "C:\\Jenkinshome\\jobs\\mablTest_Run"

Module/github.py

GithubのAPIを利用するためのファイルです。
今回は以下の二つのAPIを使用します

  • issueを作成するAPI
  • 作成したissueのIDを取得するAPI

内容は前回の記事「TestRailと自動テストの連携#1 Selenium/Python編」とほぼ同じですが、issueの本文に失敗したmablのテスト結果URLを入れるようにしました。

import json
import requests

import Module.config as config


class GithubAPIClient:
    def __init__(self):
        self.GITHUB_TOKEN = config.token_github
        self.base_url = config.base_url_github

    def create_issue(self, title, body):
        """Githubにissueを作成する
        """
        uri = f"/issues"
        url = self.base_url + uri
        headers = {}
        headers['Authorization'] = 'Bearer ' + self.GITHUB_TOKEN
        headers['Content-Type'] = 'application/json'
        headers['Accept'] = 'application/vnd.github.v3+json'
        data = {}
        data["title"] = title
        data["body"] = "こちらのリンクからテスト結果を確認してください。" + body
        payload = bytes(json.dumps(data), 'utf-8')
        response = requests.post(url, headers=headers, data=payload)
        return response

    def get_issues(self):
        """issueのデータを取得する。"
        作ったすぐ後に取得するため、一番最初のnumberを取得するようになっています。
        """
        uri = f"/issues"
        url = self.base_url + uri
        headers = {}
        headers['Authorization'] = 'Bearer ' + self.GITHUB_TOKEN
        # headers['Content-Type'] = 'application/json'
        headers['Accept'] = 'application/vnd.github.v3+json'
        response = requests.get(url, headers=headers)
        return response.json()

class APIError(Exception):
    pass

Module/testrail.py

TestRailのAPIを利用するためのファイルです。
前回の記事「TestRailと自動テストの連携#1 Selenium/Python編」と同じなので省略します。

main.py

mablのテスト結果をJenkinsのログから取得して、Githubに起票、TestRailにテスト結果の入力をします。

import csv

from Module.github import GithubAPIClient
from Module.testrail import APIClient
from Module.config import jenkins_folder

Github = GithubAPIClient()
TestRail = APIClient()

def load_csv():
    """csvファイルを読み込む。
    """
    with open(r"Data\test_data.csv", encoding='utf-8') as test_data_file:
        data = csv.DictReader(test_data_file)
        read_data = [row for row in data]
        return read_data

try:
    # 次回のビルドナンバーをジョブフォルダ内の「nextBuildNumber」ファイルから取得する。
    nextbuild_num = open(jenkins_folder + "\\nextBuildNumber", 'r')
    # 今回のビルドナンバーはマイナス1
    build_num = int(nextbuild_num.read()) - 1
    nextbuild_num.close()
except:
    # 初回は「nextBuildNumber」ファイルがないので 1
    build_num = 1

# テスト結果のログが格納されているJenkinsのフォルダを指定
job_folder = jenkins_folder + "\\builds\\"
build_folder = job_folder + str(build_num)

# ログファイルを読み込む
log = open(build_folder + "\\log", 'r')
log_text = log.read()

# 全てのテスト結果が載っている一番最後の"Running mabl test(s) status update:"の位置を探す
start_point = log_text.rfind("Running mabl test(s) status update:")
# テスト終了時に出力される"The final plan states in mabl:"の位置を探す
end_point = log_text.find("The final plan states in mabl:")
# 必要な部分だけにする
slice_area = slice(start_point, end_point)
log_text = log_text[slice_area]
# 一行ずつリストにしておく
log_list = log_text.split("\n")

# 結果を入れる辞書を用意する
test_order = 1
test_data = {}

# Jenkinsのコンソールログから、テスト結果に必要な情報を取得する
for l in log_list:
    # "Test ["の有無でテスト結果のテキストか判断する
    start_point = l.find("Test [")
    end_point = l.find("]")

    if start_point < 0:
        pass  # findの結果が0未満の場合はテスト結果のテキストではない。処理しない。
    else:
        # 1. テスト名の抽出
        # "Test [" から次の "]"までを切り取る処理
        slice_area = slice(start_point + 6, end_point)
        test_name = l[slice_area]

        # 2. テスト結果の抽出
        # Test [{テスト名}] is [" から次の "]"までを切り取る処理
        start_point = l.find("] is [")
        end_point = l.find("]", start_point + 1)

        slice_area = slice(start_point + 6, end_point)
        test_result = l[slice_area]

        # Failed の時にだけ記載される"] as ["があるかを確認
        start_point = l.find("] at [")
        end_point = l.find("]", start_point + 1)

        if start_point < 0:
            test_data[test_order] = {"name": test_name,
                                     "result": test_result, "link": ""}
            test_order = test_order + 1
            pass  # 0未満の場合はFailedではないので処理しない
        else:
            # 3. faildのテスト結果のリンクを取得
            # "] at ["から次の "]" までを切り取る処理
            slice_area = slice(start_point + 6, end_point)
            test_link = l[slice_area]
            test_data[test_order] = {"name": test_name, "result": test_result, "link": test_link}
            test_order = test_order + 1

# Githubに失敗したテストを起票
i = 1
while i < test_order:
    if test_data[i]["result"] == "failed":
        Github.create_issue("テスト失敗報告 : " + test_data[i]["name"], test_data[i]["link"])
        # issue番号を取得してtest_dataに入れる
        issue_data = Github.get_issues()
        test_data[i]["issueNum"] = issue_data[0]["number"]
        i += 1
    else:
        i += 1
        pass

# Jenkinsのログのテスト順は読み込まれた順になるため、毎回並び順が異なる。
# TestRailにインポートしたテスト項目書「test_data.csv」のテスト名と、test_dataのテスト名を照合し、
# TestIDをtest_dataに追加する。
# WARNING: テスト名は全てユニークである必要があります。
# WARNING: mablのテスト名と完全に一致している必要があります。一文字でも違うとこれ以降の処理が失敗します。
t = load_csv()
i = 1
for csv_data in t:
    y = csv_data["objectives"]
    while i < test_order:
        try: # すでにtestIDが入っているか確認。入っていたらtestID追加の処理はしない。
            test_data[i]["testID"] == ".*"
        except:
            if test_data[i]["name"] == csv_data["objectives"]:
                test_data[i]["testID"] = csv_data["testID"]
                i = 1
                break
            else:
                pass
        i += 1
        

# TestRailに結果を入力する。
i = 1
while i < test_order:
    if test_data[i]["result"] == "completed":
        TestRail.post_test_result_Pass(test_data[i]["testID"])
        i += 1
    elif test_data[i]["result"] == "failed":
        TestRail.post_test_result_Fail(test_data[i]["testID"], 
                                       "テストが失敗しました。欠陥のリンクを確認してください。", 
                                       str(test_data[i]["issueNum"]))
        i += 1
    elif test_data[i]["result"] == "skipped":
        i += 1
        pass

連携手順⑤Jenkinsのジョブを作成する

mablプラグインを利用し、指定したテストを実行する

  1. Jenkinsのサイドメニューから「新規ジョブ作成」を押します
  2. ジョブ名を入れます
  3. 「フリースタイル・プロジェクトのビルド」を選択し、「OK」を押します
  4. 「ビルド」にある「ビルド手順の追加」のプルダウンから「Run mabl tests」を選択し、以下の内容を入力します
    (1) API Key Secret:前の手順で追加したmablのAPI Keyを選択します
    (2) Application:テスト対象のアプリを選択します
    (3) Environment:テスト対象の環境を選択します

テスト結果を入力するPythonファイルを実行する

1.「ビルド手順の追加」のプルダウンから「Windowsバッチコマンドの実行」を選択し、以下のコマンドを入力します

cd {サンプルプロジェクトのmain.pyがある場所}

python main.py

2.「保存」を押します

実行手順

上記の手順で作成したJenkinsのジョブを実行するだけです。
TestRailやGithubのページを更新すると、自動的に結果の入力やissueの作成がされていることを確認できます。

おわりに

「何だこのコードはっ!! よくもこんなコードをこの海〇〇山の前に出したなっ!!こんなコードで自動化連携ができるか、不愉快だっ!!」
となったそこのあなた。一緒に頑張って乗り越えましょう!

mabl関連記事

SHARE

  • facebook
  • twitter

SQRIPTER

AGEST Engineers

AGEST

記事一覧

AGESTのエンジニアが情報発信してます!

株式会社AGEST

Sqriptsはシステム開発における品質(Quality)を中心に、エンジニアが”理解しやすい”Scriptに変換して情報発信するメディアです

  • 新規登録/ログイン
  • 株式会社AGEST