第11章 テストおよびデバッグ

11.1. 単体テスト

11.1.1. 単体テスト

ビジネスプロセスは、実装の詳細を組み込まず、ハイレベルで設計する必要があります。しかし、他の開発からの成果物と同様、それぞれライフサイクルがありビジネスプロセスは動的に更新されるため、ビジネスプロセスのテストを行うことは重要です。
特定のユースケースで予想どおりにプロセスが動作するように、特定の入力をもとに出力をテストするなど、単体テストを実施します。単体テストの簡素化のため、helper クラス JbpmJUnitTestCase (jbpm-test モジュール) が同梱されています。JbpmJUnitTestCase には以下が含まれています。
  • 一定のプロセスで新規ナレッジベースとセッションを作成するための Helper メソッド
  • 確認するための Assert ステートメント
    • プロセスインスタンスのステータス (active、completed、aborted)
    • どのノードインスタンスが現在アクティブであるか
    • どのノードがトリガーされたか (辿ってきたパスの確認)
    • 変数の値
以下の図には、開始イベント、スクリプトタスク、終了イベントが含まれています。junit テストの例では、新しいセッションの作成やプロセスの開始が行われるだけでなくプロセスインスタンスが正常に完了したことをもとに検証が行われます。また、これらの 3 つのノードが実行されたかどうかもチェックします。
hello world プロセスの例

図11.1 Hello World プロセスの例

例11.1 junit テストの例

public class MyProcessTest extends JbpmJUnitTestCase {

   public void testProcess() {
       // create your session and load the given process(es)
       StatefulKnowledgeSession ksession = createKnowledgeSession("sample.bpmn");
       // start the process
       ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello");
       // check whether the process instance has completed successfully
       assertProcessInstanceCompleted(processInstance.getId(), ksession);
       // check whether the given nodes were executed during the process execution
       assertNodeTriggered(processInstance.getId(), "StartProcess", "Hello", "EndProcess");
    }
}

11.1.2. セッション作成のための Helper メソッド

エンジンとの対話に使用するナレッジベースやセッションの作成を簡素化するために、複数のメソッドが提供されています。
createKnowledgeBase(String... process):
任意のファイル名 (クラスパスからロード) にある全プロセスを含む新しいナレッジベースを返します。
createKnowledgeBase(Map<String, ResourceType> resources):
任意のファイル名 (クラスパスからロード) からの全リソースを含む新しいナレッジベースを返します。
createKnowledgeBaseGuvnor(String... packages):
任意のパッケージの Guvnor (プロセスレポジトリ) からロードされた全プロセスを含む新しいナレッジベースを返します。
createKnowledgeSession(KnowledgeBase kbase):
任意のナレッジベースから新しいステートフルナレッジセッションを作成します。
restoreSession(StatefulKnowledgeSession ksession, boolean noCache):
データベースからこのセッションを完全にリストアします。致命的な問題が発生した場合や試験的なリカバリをシミュレーションするためにセッションを再作成する際に利用可能です。noCache が true の場合、既存の永続キャッシュを使用せずにデータをリストアします。

11.1.3. アサーション

以下のアサーションは、プロセスインスタンスの現在のステータスを円滑にテストするために提供されています。
assertProcessInstanceActive(long processInstanceId, StatefulKnowledgeSession ksession):
指定の ID のプロセスインスタンスがまだアクティブな状態にあるかどうかを確認します。
assertProcessInstanceCompleted(long processInstanceId, StatefulKnowledgeSession ksession):
指定の ID のプロセスインスタンスが正常に完了したかどうかを確認します。
assertProcessInstanceAborted(long processInstanceId, StatefulKnowledgeSession ksession):
指定の ID のプロセスインスタンスが中断されたかどうかを確認します。
assertNodeActive(long processInstanceId, StatefulKnowledgeSession ksession, String... name):
指定の ID のプロセスインスタンスに指定のノード名を持つアクティブなノードが最低 1 つ含まれているかどうかを確認します。
assertNodeTriggered(long processInstanceId, String... nodeNames):
指定のノード名を持つプロセスインスタンスを実行中にノードインスタンスが (すでにアクティブな状態でなくなっていても) トリガーされたかどうか、1 つずつ指定のノード名を確認します。
getVariableValue(String name, long processInstanceId, StatefulKnowledgeSession ksession):
指定のプロセスインスタンスから指定の名前を持つ変数の値をリトリーブします。その後プロセス変数の値をチェックするために利用することができます。

11.1.4. 外部サービスとの統合のテスト

ドメイン固有プロセスを使用すると、テスト用ハンドラーを使用して固有のサービスが正しく依頼されたかどうかを確認することができます。
TestWorkItemHandler はデフォルトで提供されており、指定の型の作業アイテムをすべて収集するために登録することが可能です (各作業アイテムは、q 固有の e-メールの送信、q 固有サービスの呼び出しなど作業単位 1 つを表しており、タスクに関するデータがすべて含まれています)。テストハンドラーは単体テスト時に照会可能で、固有の作業がプロセス実行時に実際に依頼されているかどうか、そして作業に関連付けられているデータが正しいかどうかを確認します。
以下の例は、E-メール送信プロセスがどのようにテストされるかが記述されています。このテスト事例では、E-メールが送信できなかった場合に例外が送出されるかどうかをテストします (E-メールの送信が完了できなかった旨をエンジンに通知することでシミュレーション)。また、このテスト事例では E-メールが依頼されデータがその依頼と関連付けられた際に登録するだけのテストハンドラーを使用します。エンジンに E-メールの送信ができなかった旨を (abortWorkItem(..) を使用して) 通知すると、単体テストでは、プロセスが送信不可のログを残してエラーを生成してこの事例を正しく処理し、プロセスインスタンスを中断するかどうかを検証します。
E-メールプロセスをどのようにチェックするか示した図
public void testProcess2() {
    // create your session and load the given process(es)
    StatefulKnowledgeSession ksession = createKnowledgeSession("sample2.bpmn");
    // register a test handler for "Email"
    TestWorkItemHandler testHandler = new TestWorkItemHandler();
    ksession.getWorkItemManager().registerWorkItemHandler("Email", testHandler);
    // start the process
    ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello2");
    assertProcessInstanceActive(processInstance.getId(), ksession);
    assertNodeTriggered(processInstance.getId(), "StartProcess", "Email");
    // check whether the email has been requested
    WorkItem workItem = testHandler.getWorkItem();
    assertNotNull(workItem);
    assertEquals("Email", workItem.getName());
    assertEquals("me@mail.com", workItem.getParameter("From"));
    assertEquals("you@mail.com", workItem.getParameter("To"));
    // notify the engine the email has been sent
    ksession.getWorkItemManager().abortWorkItem(workItem.getId());
    assertProcessInstanceAborted(processInstance.getId(), ksession);
    assertNodeTriggered(processInstance.getId(), "Gateway", "Failed", "Error");
}

11.1.5. 永続性の設定

デフォルトでは、永続性はオフになっており、プロセスはメモリ内に存在します。
永続性をオンにするには、以下のようにテスト事例の作成時に Boolean をスーパーコンストラクターに渡し、setPersistence を true に設定します。
public class MyProcessTest extends JbpmJUnitTestCase {

    public MyProcessTest() {
        // configure this test to use persistence
        super(true);
        setPersistence(true);
    }
    ...