ページを選択

カスタム欠陥プラグインの作成

TestRail の欠陥プラグインは、TestRail をサードパーティのバグおよび課題追跡ツールと統合するのに役立ちます。TestRail には、多くの一般的なツールとの統合にすぐに使えるプラグイン スクリプトが付属しています。しかし、TestRail に付属している欠陥プラグインは、標準的な構成の欠陥追跡ツールで動作するように設計されているため、ニーズに合わせて欠陥プラグインをカスタマイズできます。

欠陥追跡ツールがカスタマイズされている場合 (たとえば、新しい必須カスタムフィールドを追加するなど)、または統合の動作を変更したい場合は、欠陥プラグインをカスタマイズすることも、新しいプラグインを構築することもできます。欠陥プラグインをカスタマイズしたり、新しいプラグインを作成したりすると、次のような場合に役立ちます。

    • 欠陥追跡ツールに必須カスタム フィールドが追加されており、それらのフィールドを [欠陥のプッシュ] ダイアログに追加したい場合。
    • デフォルトの欠陥プラグインの振る舞いを変更したい場合 (たとえば、ユーザー マッピングを追加したり、送信されるバグ レポートに情報を追加するなど)。
    • カスタム ツール/まだサポートされていないツールを使用しており、そのツールと統合したい場合。

このページでは、欠陥プラグインの基本的なアーキテクチャとカスタマイズの方法について説明します。また、 [欠陥のプッシュ] ダイアログに新しいフィールドを追加する方法、および欠陥プラグインにユーザー マッピング機能を追加する方法の具体的なサンプルもあります。

独自の欠陥プラグインを作成したものを他のユーザーと共有したい場合、パブリックな TestRail カスタマイズ GitHub リポジトリにコントリビュートしていただけます。

はじめに

欠陥プラグインは PHP で開発されているため、独自の欠陥プラグインをカスタマイズまたは作成する場合、PHP についての基本的な知識が必要です。カスタム欠陥プラグインについては、作成されたスクリプトに関するエラーの調査や解決をサポートすることはできません。PHPスクリプトの実装経験のある方の支援をお願いしてください。

アプリケーションの初期化時に TestRail が欠陥プラグインを探すディレクトリは 2 つあります。最初のディレクトリは、TestRail 組み込みのデフォルト プラグインも保存される場所です。TestRail を更新するとこれらのファイルが上書きされるため、このディレクトリのプラグイン スクリプトを追加または変更しないでください。

<TestRail>/app/plugins/defects

変更または新規追加されたプラグイン スクリプトは、常にカスタム欠陥プラグインのディレクトリに配置する必要があります。

<TestRail>/custom/defects

プラグイン ファイル

欠陥プラグインは、 TestRail が欠陥追跡ツールとの通信に使用するクラスを実装した単純な PHP スクリプトです。欠陥プラグインをカスタマイズしたり独自の欠陥プラグインを作成する場合、上記のアプリケーション ディレクトリからカスタム欠陥プラグイン ディレクトリに既存のスクリプトをコピーし、ファイルの名前を変更して利用できます。あるいは、以下のスクリプト スケルトンから始めることもできます。

たとえば、TestRail の Jira 欠陥プラグインをカスタマイズしたい場合は、<TestRail>/app/plugins/defects から <TestRail>/custom/defects にファイルをコピーします。TestRail は欠陥プラグインのファイル名を一意の (クラス) 識別子として使用するため、ファイルの名前を変更する必要があります。たとえば、ファイル名を  Jira_ExampleInc.php に変更して、組織の名前または TestRail と統合したいカスタム ツールの名前を含めることができます。ファイル名と一致するように欠陥クラス名を調整する方法については、次のセクションを参照してください。

プラグインの基本

欠陥プラグインは、 TestRail が欠陥追跡ツールとの通信に使用するメソッドを実装した単純な PHP クラスです。TestRail はスクリプトのファイル名をスクリプトの一意の識別子として使用します。プラグイン クラス名はファイル名に基づいている必要があります。たとえば、プラグイン スクリプト ファイルの名前が Jira.php である場合、プラグイン クラス名は Jira_defect_plugin という名前にする必要があります。

すべての欠陥プラグイン クラスは TestRail の  Defect_plugin 基底クラスを拡張する必要があります。次のクラス スケルトンは、すべての基底メソッドを実装し、基本的なメソッドと引数を説明しています。

// MyPlugin.php
class MyPlugin_defect_plugin extends Defect_plugin
{
  // Get Meta
  //
  // Expected to return meta data for this plugin such as Author,
  // Version, Description and supported plugin capabilities.
  public function get_meta()
  {
  }
 
  // Validate Config
  //
  // Validates the plugin configuration that is entered in the site
  // or project settings. Expected to throw a ValidationException
  // in case the passed configuration does not validate.
  public function validate_config($config)
  {
  }
 
  // Configure
  //
  // Passes the configuration for the plugin as specified in the
  // site or project settings (as string).
  public function configure($config)
  {
  }
 
  // Prepare Push
  //
  // Signals if the plugin requires/supports a form to submit the
  // defect. Returns 'false' to signal that no form is required.
  // Otherwise the plugin should return the form description that
  // is used to render the form and display it to the user.
  public function prepare_push($context)
  {
  }
 
  // Prepare Field
  //
  // Called for each field of the push form to gather the field
  // data for the form. The plugin can return default values or
  // available options for the field (in case of a dropdown
  // box, for example), among other values.
  public function prepare_field($context, $input, $field)
  {
  }
 
  // Validate Push
  //
  // Called before the actual push attempt is processed (in case
  // the plugin uses a custom form). Useful for adding custom
  // validation functionality for the form that is not covered by
  // TestRail itself. Expected to throw a ValidationException in
  // case the passed input of the custom form does not validate.
  public function validate_push($context, $input)
  {
  }
 
  // Push
  //
  // Executes the actual push request by adding a new case to the
  // defect tracker. Expected to return the new defect ID (as
  // string or integer).
  public function push($context, $input)
  {
  }
 
  // Lookup
  //
  // Looks up the defect/issue/case with the given ID and returns
  // its properties as key/value array. The following return values
  // are required:
  // 
  // id:           The ID of the defect (usually the same as the
  //               passed ID)
  // title:        The title/summary of the defect
  // status_id:    The status ID of the defect. Possible values
  //               are:
  //               - GI_DEFECTS_STATUS_OPEN
  //               - GI_DEFECTS_STATUS_RESOLVED
  //               - GI_DEFECTS_STATUS_CLOSED
  // status:       The status as text
  // 	             
  //
  // The following properties are optional:
  //
  // url:          The full HTTP url to view the defect
  // description:  The description of the defect (supports HTML,
  //               the plugin is responsible for providing well-
  //               formed and valid HTML and must escape data
  //               that is not expected to be rendered as HTML).
  // attributes:   A key/value list of additional attributes.
  //               The value also supports HTML with the same
  //               implications as for the description.
  public function lookup($defect_id)
  {
  }
}

ただし、必ずしもすべてのメソッドを完全に実装する必要はありません。欠陥プラグインには (現在のところ) 2 つの機能があります。欠陥を外部アプリケーションにプッシュすることと欠陥情報を検索することです。作成しようとしているプラグインやコンテキストによっては、これらの機能のうちの 1 つだけを実装することが理にかなっている場合があります。

たとえば、テスターが [欠陥のプッシュ] ダイアログから電子メールを送信できるようにするプラグインを実装する場合、検索機能を実装する必要はありません。同様に、欠陥追跡ツールから欠陥情報を取得するが、バグ レポート フォームは欠陥追跡ツールのものを使用したい場合は、プッシュ機能を実装する必要はありません。

欠陥プラグインは非常に柔軟です。たとえば、現在 TestRail に付属しているすべての欠陥プラグインは、テスターが入力済みのバグ レポートをカスタマイズできるようダイアログを表示しますが、ダイアログの表示は必須ではありません。欠陥プラグインは、ユーザーの介入なしにバックグラウンドで自動的にバグ レポートを送信できます。

独自のプラグインを構築する

このセクションでは、欠陥プラグインを作成する手順を詳しく説明し、さまざまなプラグイン メソッドと特徴について説明します。独自のプラグインを一から作成する予定はなく、単に既存のプラグインをカスタマイズしたい場合も、このセクションを参照することは、プラグインの内部の仕組みについて学ぶための最良の方法です。ここでは、架空のバグ追跡ツール Bugs 用の新しい欠陥プラグインを作成します。以降のセクションでは、新しいプラグインを作成する手順について説明します。

プラグインの作成を始める前に、TestRail はすべての文字列とテキストが UTF-8 エンコーディングであると期待する (そして TestRail が提供するテキストも UTF-8 エンコーディングである) ことに注意が必要です。つまり、TestRail に返却する (または TestRail から受け取る) すべての文字列とテキストは UTF-8 でエンコードする必要があります。これは、欧米以外の文字を処理する場合は特に重要ですが、ASCII 以外の特殊文字なども考慮する必要があります。

ファイルの作成

新しい欠陥プラグインを作成する際の最初のステップは、スクリプト ファイルの作成です。

この例では、ファイル名を Bug.php とし、TestRail のカスタム 欠陥プラグインのディレクトリ (<TestRail>/custom/defects) に配置します。既存の欠陥プラグインを利用する場合 (デフォルトの欠陥プラグインはすべて完全なソースコードで提供されています。<TestRail>/app/plugins/defects ディレクトリにあります)、それをカスタム欠陥プラグインのディレクトリにコピーして名前を変更してください。Bugsの基本的な欠陥プラグインは次のようになります (<?php タグをファイルの最後で閉じないことに注意してください。これにより、ファイル末尾の空の行によって PHP のヘッダー出力が壊れるのを防ぎます)。

class Bugs_defect_plugin extends Defect_plugin
{
}

メタ データを返す

最初に実装するのは get_meta メソッドです。このメソッドは、作成者の名前、プラグインのバージョン、サポートされている機能、設定の詳細など、プラグインに関する情報を TestRail に通知します。そのため、このメソッドは次のように、情報を含む配列を返します。

{
  return array(
    'author' => 'Example Inc.',
    'version' => '1.0',
    'description' => 'Bugs defect plugin for TestRail',
    'can_push' => false,
    'can_lookup' => false,
    'default_config' => 
      "; Please configure your Bugs connection below\n" .
      "[connection]\n" .
      "address=http:///\n" .
      "user=testrail\n" .
      "password=secret"
  );
}

特に重要なのは can_push および can_lookup プロパティです。これらのプロパティは、欠陥プラグインがどの機能を実装しているかを TestRail に伝えます。現時点ではプッシュ機能と検索機能しかありませんが、今後の TestRail バージョンで新しい機能が追加される可能性があります。

default_config プロパティにも注目すべきです。欠陥プラグインは、 [管理] > [統合] の下でグローバルに、または [管理] > [プロジェクト] の下でプロジェクトごとに設定できます。管理者がプラグインを設定するとき、default_config で指定されているデフォルトの設定が設定テキスト フィールドにロードされます。

設定

通常、欠陥プラグインには欠陥追跡システムのアドレス、ユーザー名およびパスワードなどのオプションを設定する必要があります。管理者が TestRail で欠陥プラグインを設定する際、テキスト フィールドを使用して設定を入力します。テキスト フィールドはさまざまな表記法 (INI オプション、XML など) をサポートしているため、プラグインは独自の設定フォーマットを使用できます。

TestRail のデフォルトの欠陥プラグインは、設定に INI ファイル表記を使用するため、[sections]name=value ペアを使用して設定を指定します。TestRail は INI 表記された設定オプションを読み取るメソッドを備えているため、通常は INI 表記を使うことが推奨されます。

管理者がプラグインを設定すると、TestRail は入力された設定を確認するようにプラグインに要求します。TestRail は必要な設定 (あるいは設定のフォーマットさえ) についての情報を持っていないので、すべての必要な設定が指定されていることを欠陥プラグインが検証する必要があります。そのため、TestRail は管理者が設定を変更しようとするたびに validate_config メソッドを呼び出します。

public function validate_config($config)
{
  $ini = ini::parse($config);
 
  // Check if the [connection] section exists
  if (!isset($ini['connection']))
  {
    throw new ValidationException('Missing [connection] group');
  }
 
  // Check if the required values exist
  $keys = array('address', 'user', 'password');
  foreach ($keys as $key)
  {
    if (!isset($ini['connection'][$key]) ||
      !$ini['connection'][$key])
    {
      throw new ValidationException(
        "Missing configuration for key '$key'"
      );
    }
  }
 
  $address = $ini['connection']['address'];
 
  // Check whether the address is a valid url (syntax only)
  if (!check::url($address))
  {
    throw new ValidationException('Address is not a valid url');
  }
}

上記のメソッドは、[connection] セクションが存在し、セクションに addressuser、および password キーが含まれていることを確認します。また、password キーに有効な URL が含まれていることを ( check::url  ルーチンを使用して) 確認します。また、メソッドの冒頭で TestRail の ini モジュールを使用して設定を解析していることにも注目してください。メソッドが設定の問題 (キーの欠落、無効な値など) を検出した場合 ValidationException 型の例外を上げます。すると、TestRail が管理者にエラー メッセージを表示します。

設定が完了したら、プラグインが設定にアクセスする方法が必要です。TestRail は、欠陥クラスがインスタンス化されるたびに自動的に configure メソッドを呼び出します。たとえば、TestRail は欠陥プラグインに欠陥 ID の検索を依頼する前に configure メソッドを呼び出して、必要なすべての設定をプラグインに提供します。インスタンスがアクティブである間、プラグインはこれらの設定を保持し、メソッドが呼び出されたときに設定にアクセスできるようにする必要があります。これを実現するために、プラグインは通常、設定をインスタンス変数に格納します。

public function configure($config)
{
  $ini = ini::parse($config);
  $this->_address = str::slash($ini['connection']['address']);
  $this->_user = $ini['connection']['user'];
  $this->_password = $ini['connection']['password'];	
}

メソッドは ini モジュールを介して設定を再度解析し、設定をインスタンス変数/フィールドに保存します。その後のメソッド呼び出しで欠陥追跡システムのアドレスにアクセスするには、 $this→_address を使用します。

欠陥を検索する

まず、欠陥検索機能について説明します。この機能は、欠陥プッシュ機能よりも実装が簡単であるため、欠陥プラグインがどのように機能するかをよりよく理解するのに適しているからです。TestRail が入力された欠陥 ID を (たとえばテスト結果の一部として) レンダリングするとき、欠陥プラグインが設定されている場合、プラグインが欠陥の検索をサポートしているかどうかをチェックします ( get_meta によって返される can_lookup オプションをチェックすることによって)。

プラグインが検索機能をサポートしている場合、ユーザーがマウス カーソルを欠陥 ID の上に移動すると、欠陥のステータスと説明の詳細を参照できます。ユーザーがこの操作を実行するたびに、データを表示するために、TestRail は 欠陥プラグインに欠陥に関する情報を取得するように要求します (参考までに、今後、レポート用にオープン中/クローズ済みの欠陥を計算するなど、他の目的でこの情報が使用される可能性があります)。

欠陥情報の要求は、lookup メソッドによって行われます。このメソッドが呼び出される前に、TestRail は常に configure メソッドを呼び出して、プラグインに必要な設定がすべて存在することを確認します。架空の欠陥追跡システム Bugs lookup メソッドは、次のとおりです。

public function lookup($defect_id)
{
  // Get the defect information via the Bugs API
  $defect = $this->_bugs_get_defect($defect_id);
 
  // Build the status_id based on the status property
  if ($defect['status'] == 'Open')
  {
    $status_id = GI_DEFECTS_STATUS_OPEN;
  }
  elseif ($defect['status'] == 'Resolved')
  {
    $status_id = GI_DEFECTS_STATUS_RESOLVED;
  }
  else
  {
    $status_id = GI_DEFECTS_STATUS_CLOSED;
  }
 
  // Build the bug URL and project link
  $bug_url = str::format('{0}?bug={1}', 
    $this->_address,
    $defect['id']);
  $project_link = str::format(
    '{2}',
    a($this->_address),
    a($defect['project_id']),
    h($defect['project']));
 
  // Build the description
  $description = str::format(
    '{0}',
    nl2br(
      html::link_urls(
        h($defect['description'])
      )
    )
  );	
 
  // Return the defect details
  return array(
    'id' => $defect['id'],
    'title' => $defect['title'],
    'status_id' => $status_id,
    'status' => $defect['status'],
    'url' => $bug_url,
    'description' => $description,
    'attributes' => array(
      'Type' => h($defect['type']),
      'Status' => h($defect['status']),
      'Project' => $project_link
    )
  );
}

このメソッドは、これまで見てきた他のメソッド実装よりも少し長いので、メソッドが実行するステップを個別に見てみましょう。まず、internal/private _bugs_get_defect メソッドを呼び出して、欠陥の詳細を取得します。このメソッド (または類似のメソッド) は通常、欠陥追跡システムの API を呼び出すか、データベースの欠陥情報を検索します。このサンプル プラグインのソース コードを以下からダウンロードすると、このメソッドが単にすべての欠陥の詳細をハードコードしており、実際には Web サービスの呼び出しを行っていないことに気付くでしょうが、デモ目的ではこれでじゅうぶんです。

その後、TestRail に返す status_id やリンク、説明などの値を準備します。 status_id  は、欠陥が open であるか resolved であるか、または closed であるかを TestRail に伝えます。バグ トラッカーが resolved と closed を区別しない場合 (バグは opened か resolved のどちらかである場合など)、 GI_DEFECTS_STATUS_CLOSED ステータスを指定します。TestRail は、今後、レポートおよびその他の機能で status_id を使用する可能性があります。

lookup メソッドが返すフィールドのいくつかは HTML をサポートしています。これは、TestRail に返す前に文字列や値をエスケープすることが重要であることを意味します (バグ トラッカーが返す値が有効な HTML データではない場合)。エスケープを行わないと、クロス サイト スクリプティング (XSS) 攻撃の危険性があり、潜在的なセキュリティ リスクとなります。文字列をエスケープするには、TestRail が提供する h()  および a() ルーチンを使用して、それぞれテキストとタグ属性をエスケープします。たとえば、返される属性に HTML コード (リンクなど) が含まれる場合があります。プロジェクト名などの値をエスケープしないと、TestRail はそれらをそのままレンダリングするため、攻撃者がプロジェクト名を介して JavaScript コードを挿入する可能性があります。また、メソッドが  div タグでバグの説明をラップし、説明を等幅フォントでフォーマットしていることにも注目してください。

最後に重要な処理として、メソッドは TestRail に欠陥の詳細を返します。欠陥 ID、タイトル、ステータスなどの情報のほかに、属性と説明を返すこともできます。属性には、プロジェクト、課題タイプ、コンポーネント、またはプロジェクト領域などの情報を含めることができます。属性と同じように、説明は HTML をサポートしているため、どんな種類の情報を追加するのにも使用できます。HTML タグが壊れていると、TestRail のレイアウトや機能が壊れる可能性があるため、返されたすべての HTML に含まれるタグやフォーマットが有効であることを確認してください。次のスクリーン ショットは、返された欠陥の情報を TestRail がどのようにレンダリングするかを示しています (説明の上部に青い背景で属性がレンダリングされていることに注目してください)。

ダイアログなしで欠陥をプッシュする

次に、TestRail から欠陥レポートを欠陥追跡ツールにプッシュする方法を見てみましょう。最初にプッシュ ダイアログなしでプッシュ機能を実装し、次のセクションでプッシュ ダイアログを使ったより複雑なシナリオを見ていきます。プッシュ ダイアログなしでプッシュ機能を実装する場合、2 つの メソッドを使用します。prepare_pushpush です。TestRail は prepare_push メソッドを呼び出して、レンダリングする必要があるダイアログおよびフィールドに関する情報を要求します。プッシュ ダイアログを必要とせず、ユーザーの操作なしでバグ レポートをプッシュしたいだけの場合は、単に false を返します。

public function prepare_push($context)
{
  return false;
}

実際に欠陥をプッシュするために、push メソッドも実装する必要があります。有用な欠陥レポートを作成するには、もちろんテストに関する情報 (ケースのタイトルや入力されたコメントなど) が必要ですし、欠陥をプッシュするユーザーなど、その他の情報が必要な場合もあります。そこで、プッシュ関連のすべてのメソッドに渡される $context 引数を利用すると便利です。 $context 引数には、テスト ケースに関する詳細、テスト、欠陥をプッシュしようとしているユーザーなど、多くの有用なコンテキスト情報が含まれています。 $context 引数を介して渡される情報をいくつかを見てみましょう。

Array
(
    [event] => push
    [tests] => Array
        (
            [0] => stdClass Object
                (
                    [id] => 12
                    [run_id] => 1
                    [case_id] => 128
                    [status_id] => 1
                    [url] => http://testrail/index.php?/tests/view/12
                    [case] => stdClass Object
                        (
                            [id] => 128
                            [title] => Verify CSV import with enclosed test data files
                            [url] => http://testrail/index.php?/cases/view/128
                        )

                    [run] => stdClass Object
                        (
                            [id] => 1
                            [name] => File Formats
                            [config] => 
                            [plan_id] => 
                            [project_id] => 1
                            [url] => http://testrail/index.php?/runs/view/1
                        )

                )

        )

    [test_count] => 1
    [test_change] => stdClass Object
        (
            [status_id] => 1
            [assignedto] => 
            [comment] => Importing our standard Unicode CSV file (unitest1.csv) failed with the error message `Could not detect file encoding`.
            [attachments] => 
            [version] => 
            [elapsed] => 
            [defects] => 
        )

    [project] => stdClass Object
        (
            [id] => 1
            [name] => Datahub
            [url] => http://testrail/index.php?/projects/overview/1
        )

    [preferences] => Array
        (
            [type] => 1
            [project] => DH
            [component] => 10010
        )

    [user] => stdClass Object
        (
            [id] => 2
            [name] => ..
            [email] => test@example.com
        )

)

ご覧のとおり、TestRail は選択したテスト、関連するテストケース、プロジェクト、テストの変更 (ユーザーが [結果の追加] ダイアログで入力した情報) などに関する詳細を提供します。データ構造からわかるように、TestRail が欠陥プラグインに複数のテストを渡す場合があります。ユーザーが複数のテストを選択し、[結果の追加] ボタンを使用してそれらのすべてのテストに一度に結果を追加した場合、TestRail はスクリプトに複数のテスト レコードを渡します。欠陥をプッシュして新しい欠陥 ID を返す処理は、次のようになります。

public function push($context, $input)
{
  // Build the summary/title
  $test = current($context['tests']);
  $summary = 'Failed test: ' . $test->case->title;
 
  if ($context['test_count'] > 1)
  {
    $summary .= ' (+others)';
  }	
 
  // Build the comment (based on the test result comment
  // and links/URLs of the tests
  if ($context['test_change']->comment)
  {
    $comment = $context['test_change']->comment;
    $comment .= "\n";
  }
  else 
  {
    $comment = '';
  }
 
  $tests = $context['tests'];
  foreach ($tests as $test)
  {
    $comment .= "\nTest: ";
    $comment .= $test->case->title;
    $comment .= "\n";
    $comment .= $test->url;
  }
 
  // We hard code a few other details here for demonstration
  // purposes. We could also select these attributes based
  // on context information such as the test suite or user
  $project = $context['project']->name;
  $type = 'Bug';
  $component = '(default)';
 
  // Push the defect and return the new defect ID
  $defect_id = $this->_bugs_push_defect(
    $summary,
    $comment,
    $project,
    $type,
    $component
  );
  return $defect_id;
}

push メソッドは、入力されたテスト結果とコンテキスト情報に基づいてバグ レポートのタイトル/要約とコメントを作成します。その後、内部の _bugs_push_defect メソッドを呼び出して、実際のバグ レポートを送信します。このメソッドは、Web サービス API の呼び出しまたはデータベースへのバグ レポートの書き込みを実装します。新しい欠陥の ID をTestRail に返すと、TestRail が自動的に欠陥フィールドに ID を追加します。

ダイアログを使用して欠陥をプッシュする

ユーザーの操作なしでバグ レポートをプッシュする欠陥プラグインの構築を見てきたので、次に [欠陥のプッシュ] ダイアログを使用するようにプラグインを更新します。テスターは、欠陥を欠陥追跡システムにプッシュする際、このダイアログを使用して欠陥の説明を変更したり、別のプロジェクトを選択したりできます。最初に prepare_push メソッドを変更します。ダイアログが不要であることを示す false を返す代わりに、次のようなフォーム スキーマを返します。

public function prepare_push($context)
{
  // Return a form with the following fields/properties
  return array(
    'fields' => array(
      'summary' => array(
        'type' => 'string',
        'label' => 'Summary',
        'required' => true,
        'size' => 'full'
      ),
      'type' => array(
        'type' => 'dropdown',
        'label' => 'Issue Type',
        'required' => true,
        'remember' => true,
        'size' => 'compact'
      ),
      'project' => array(
        'type' => 'dropdown',
        'label' => 'Project',
        'required' => true,
        'remember' => true,
        'cascading' => true,
        'size' => 'compact'
      ),
      'component' => array(
        'type' => 'dropdown',
        'label' => 'Component',
        'required' => true,
        'remember' => true,
        'depends_on' => 'project',
        'size' => 'compact'
      ),
      'description' => array(
        'type' => 'text',
        'label' => 'Description'
      )
    )
  );
}

フォーム スキーマは、必要なフォーム フィールドを TestRail に指示します。prepare_push メソッドで返したフォーム スキーマに基づいて TestRail が自動的にプッシュ ダイアログをレンダリングするため、欠陥スクリプトがダイアログ自体をレンダリングする必要はありません。上記の例で返されるフォーム スキーマの大部分は、説明がなくともわかるでしょう。TestRail が表示するフォーム フィールドのリストを返します。

フィールドの配列キー (例えば ‘description’) は、TestRail が入力データをスクリプトに渡すために使用する名前です。フィールドの type は、現在、 textdropdown または string のいずれかで、必要なフィールドのタイプを TestRailに伝えます。string  は単一行のテキスト入力要素であり、text は複数の入力行を受け入れます 。required オプションは、ユーザーによるフィールドの入力が必須かまたは任意かを指定し、 label はダイアログ内でのフィールドの表示方法を指定します。

size オプションは、フィールドの横幅を指定します。full が指定された場合、フィールドはダイアログの横幅いっぱいの大きさになります。フィールド サイズとして compact を指定すると、TestRail は同じ行に複数の小さなフィールドを表示しようとします (これは、フォーム スキーマでひとまとまりで指定された小さなフィールドにのみ適用されます)。remember オプションを指定した場合、TestRail は現在の TestRail プロジェクトで最後に入力された値を保存します。これにより、以前に入力したフォーム値 (プロジェクト領域やサブ コンポーネントなど) を簡単に保存でき、ユーザーが同じデータを何度も入力する必要がなくなります。このセクションの後半で、これがどのように機能するのかを見ていきます。

フィールドが他のフィールドに依存する場合があります。たとえば、[プロジェクト] ドロップダウン フィールドがある場合、関連する [プロジェクト領域] フィールドの値は、選択したプロジェクトによって異なります。TestRail は、このようなケースに対応するために、フィールドの依存関係をサポートします。ユーザーが別のプロジェクトを選択した場合、TestRail は新しく選択したプロジェクトの有効なプロジェクト領域を欠陥スクリプトに要求し、[プロジェクト領域] フィールドの値をクリアします。フィールドの依存関係は depends_on オプションによって指定され、現在は、ドロップダウン フィールドでのみサポートされています。他のフィールドが依存できるフィールドを cascading としてマークする (それぞれのオプションによって) ことも必要です。

フォーム スキーマを指定したので、今度は有効なドロップダウン値とダイアログ フィールドのデフォルト テキストを TestRail に指示する必要があります。これは prepare_field メソッドを介して実行できます。TestRail がダイアログを初期化するとき、またはカスケード フィールドが変更されたとき、TestRail は関連するフィールドに関する情報を提供するように欠陥プラグインに依頼します。TestRailは、情報を必要とするすべてのフィールドに対して prepare_filed メソッドを呼び出します。

public function prepare_field($context, $input, $field)
{
  $data = array();
 
  // Take the preferences of the user into account, but only
  // for the initial form rendering (not for cascading loads).
  if ($context['event'] == 'prepare')
  {
    $prefs = arr::get($context, 'preferences');
  }
  else
  {
    $prefs = null;
  }
 
  // And then build the options and default values for the
  // form fields and return them.
  switch ($field)
  {
    case 'summary':
      $data['default'] = 
        $this->_get_summary_default($context);
      break;
 
    case 'description':
      $data['default'] = 
        $this->_get_description_default($context);
      break;
 
    case 'type':
      $data['options'] = $this->_bugs_get_types();
 
      // Select the stored preference or the first item in
      // the list otherwise.
      $default = arr::get($prefs, 'type');
      if ($default)
      {
        $data['default'] = $default;
      }
      else
      {
        if ($data['options'])
        {
          $data['default'] = key($data['options']);
        }
      }				
      break;
 
    case 'project':
      $data['default'] = arr::get($prefs, 'project');
      $data['options'] = $this->_bugs_get_projects();
      break;
 
    case 'component':
      if (isset($input['project']))
      {
        $data['default'] = arr::get($prefs, 'component');
        $data['options'] = $this->_bugs_get_components(
          $input['project']);
      }
      break;
  }
 
  return $data;
}

TestRail は prepare_field メソッドに 3 つの引数を渡します。 $context 引数には、前のメソッドから引き継いだコンテキスト情報が含まれています。$input 配列には、ユーザーがプッシュ ダイアログに入力した実際のデータが含まれています (これはカスケード ドロップダウンの呼び出し時に特に役立ちます)。$field 引数には、メソッドが呼び出されたフィールドの名前が含まれます (メソッドはフィールドに対して個別に呼び出されます)。

TestRail は $context 引数の一部として (現在のプロジェクトに対する) 現在のユーザーの設定も渡します。したがって、TestRail が現在ダイアログを初期化している場合、prepare_field メソッドが最初に行う処理は、ユーザー設定をローカル変数にコピーすることです。すでに初期化された後、カスケード ドロップダウン フィールドに対する呼び出しである場合は、設定を無視します。

その後、TestRail にフィールド用の適切なデータを返します。この例では、長い switch 文でこの処理を行います。TestRail がデータを要求しているフィールドに応じて、関連するコードを実行します。

たとえば、TestRail が Project フィールド用の値を要求した場合、次のコードが実行されます。

case 'project':
  $data['default'] = arr::get($prefs, 'project');
  $data['options'] = $this->_bugs_get_projects();
  break;

基本的に、TestRail はドロップダウン フィールドに関して 2 つの情報を必要とします。つまり、ユーザーが選択可能な options と選択されている default オプションです。テキスト フィールドおよび文字列フィールドには、default 値だけを指定します (テキスト フィールドまたは文字列フィールドには、ユーザーが選択可能なオプションはないからです)。この例では、ユーザー設定に基づいて default オプションが選択されます。そのため、ユーザーが以前に特定のプロジェクトを選択した場合は、そのプロジェクトを復元し、ユーザーがプロジェクトを再度指定する必要がないようにします。同様に、テストの詳細に基づいて、要約/タイトルと説明フィールドのデフォルトのテキストを生成します。ダイアログは、次のようになります。

この例では、_bugs_get_projects などのメソッドを完全には実装していません。完全に機能するプラグインでは、このメソッドは欠陥トラッカーの Web サービス API を使ってプロジェクトのリストを取得するでしょう (あるいはデータベースからプロジェクトのリストを読み取るでしょう)。この例では、単にハードコードされたプロジェクトのリストを返します (プロジェクトが頻繁には変更されない場合、これも有効な実装方法になり得ます)。

private function _bugs_get_projects()
{
  return array(
    'dh' => 'Datahub',
    'pr' => 'Presenter',
    'wr' => 'Writer'
  );
}

ここでは、配列キーとして ID を使用していることに注目してください。ユーザーが送信ボタンをクリックすると、TestRail はこれらの ID を入力値として push メソッドに渡します。push メソッドを実装する前に、validate_push メソッドを簡単に見てみましょう。このメソッドにより、バグ レポートに入力された値を受け入れる前にユーザー入力を検証できます。データを検証する必要がない場合は、このメソッドを実装する必要はありませんが、特定の入力形式や制約 (日付など) を強制するのに役立ちます。次の例では、validate_push メソッドを使用して、要約フィールドの文字数を 100 文字までに制限しています。

public function validate_push($context, $input) 
{ 
  if (isset($input['summary'])) 
  { 
    if (str::len($input['summary']) > 100) 
    { 
      throw new ValidationException( 'Field Summary cannot exceed 100 characters.'); 
    } 
  } 
}

ユーザーがバグ レポートを入力して送信ボタンをクリックし、スクリプトが validate_push メソッドによって入力を検証したら、TestRail は push メソッドを呼び出してバグ レポートを送信します。上記のダイアログなしの例と同様に、 push メソッドはレポートを送信します。今回は、$context 引数からバグ レポートを作成する代わりに、$input 引数を使用していることに注意してください。

public function push($context, $input)
{
  // Push the defect and return the new defect ID
  $defect_id = $this->_bugs_push_defect(
    $input['summary'],
    $input['description'],
    $input['project'],
    $input['type'],
    $input['component']
  );
  return $defect_id;
}

これで終わりです。これで、検索機能とプッシュ機能をサポートし、TestRail 内から管理者が設定でき、プロジェクト リストのカスケード ドロップダウンをサポートする欠陥プラグイン全体を正しく実装できました。下記の完全なサンプル スクリプトをダウンロードすることができるほか、その他のサンプル スクリプトを参照することもできます。

ダウンロード

このセクションで説明したサンプル スクリプト全体は、ここからダウンロードできます。

実際の欠陥プラグインの他の例を見るには、TestRail に同梱されている欠陥プラグインを見てみることをお勧めします。欠陥プラグインは TestRail のインストールディレクトリの app/plugins/defects にあります。