UiPath Studioの「コード化されたテストケース」と「オブジェクトリポジトリ」を使って、削除された画面要素を検知したい！

# はじめに

以前、UiPath StudioとGitを使ってWEB画面の変化を捉えよう、という試みの記事を書きました。

https://qiita.com/moripo/items/19a134701e31c772794e

この方法には課題があります。
それは **削除されている要素が検知できない** ことです。
対応策として、チェックする手順を整理しましたのでご紹介します。

今回活用するのは **Studio v23.10** で追加された **「コード化されたテストケース」** です。

https://docs.uipath.com/ja/studio/standalone/2023.10/user-guide/coded-test-case


# 「コード化されたテストケース」で要素有無のチェックをする処理を実装します。

この方法は **「コード化されたテストケース」** でも可能です。

当記事で対象と想定するのは、前回同様、以下のRPA Challegeのページです。

https://rpachallenge.com/?lang=JA

### ■ 手順

:::note 
事前にプロジェクト内にRPA Challegeのオブジェクトリポジトリが定義されている前提の手順です。
オブジェクトリポジトリが定義済であれば、読み替えていただくことも可能です。
:::

#### ① 右クリックで **「コード化されたテストケース」** を作成します。

:::note warn
**「コード化されたワークフロー」** でも実行可能ですが、コードの貼り付け時に ```[Workflow]```の文字列を```[TestCase]```で上書きしないようにご注意ください。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/dff25925-e6a2-edea-210e-cbf60b18b927.png)

#### ② 以下のコードの namespace 以下のブロックをコピー＆ペーストします。

**基本的な手順は以上** です。環境や要件に合わせて微修正をして実行します。

```テストケース.cs
using System;
using System.Collections.Generic;
using System.Data;
using UiPath.CodedWorkflows;
using UiPath.Core;
using UiPath.Core.Activities.Storage;
using UiPath.Orchestrator.Client.Models;
using UiPath.Testing;
using UiPath.Testing.Activities.TestData;
using UiPath.Testing.Activities.TestDataQueues.Enums;
using UiPath.Testing.Enums;
using UiPath.UIAutomationNext.API.Contracts;
using UiPath.UIAutomationNext.API.Models;
using UiPath.UIAutomationNext.Enums;
using CodedRpaChallenge.ObjectRepository;
using System.Threading.Tasks;

namespace CodedRpaChallenge
{
    public class テストケース : CodedWorkflow
    {
        
        // アプリケーションを開く際のオプション指定
        public TargetAppOptions targetAppOptions => new TargetAppOptions() {
            InteractionMode = NInteractionMode.Simulate,
            OpenMode = NAppOpenMode.IfNotOpen,
            AttachMode = NAppAttachMode.SingleWindow
        };
       
        // IsEnable のプロパティ　※特に、要素が無い場合の待ちをなくすためTimeoutの設定を推奨
        public IsEnabledOptions isEnableOptions => new IsEnabledOptions() {
            DelayBefore = 0,
            DelayAfter = 0,
            Timeout = 0
        };
        
        // チェックする要素名の配列
        string[] elements = new string[] {"開始", "苗字", "名前", "会社名", "部署", "住所", "メールアドレス", "電話番号"};

        
        [TestCase]
        public void Execute()
        {
            // 並列処理のオプション、一旦５並列で…
            ParallelOptions parallelOptions = new ParallelOptions();
            parallelOptions.MaxDegreeOfParallelism = 5;
            
            Log("Test run started for テストケース.");
            
            // 対象のアプリケーション画面を開きます。
            UiTargetApp screen = uiAutomation.Open("Chrome: Rpa Challenge", targetAppOptions);

            // 繰り返しの中で、要素の有無をコンソールに出力する。
            Parallel.ForEach(elements, parallelOptions, s =>
            {
                // 繰り返しの都度、初期化します。
                bool isEnabled = false;
                bool noException = true;
                try {
                    isEnabled = screen.IsEnabled(s, isEnableOptions);
                } catch ( Exception e ) {
                    // 当ケースでは、例外発生時は検証失敗とします。
                    noException = false;
                }
                // テストの検証関数
                testing.VerifyExpression( noException , string.Format("要素 [{0}] をチェックし、結果は [{1}] でした。",s, isEnabled.ToString()) , true, s, false, false);

            });
        }
    }
}
```

:::note 

```testing.VerifyExpression```が結果をチェックするテスト系（検証用）の関数です。
以下の引数を持つものを使用しました。
```
bool VerifyExpression(
	bool 検証する式,
	string 出力メッセージフォーマット,
	bool 失敗時に継続する,
	string 代替タイトル,
	bool 失敗した場合はスクリーンショットを撮る,
	bool 成功した場合はスクリーンショットを撮る
)
```

VerifyExpressionの詳細は以下をご参照ください。
https://docs.uipath.com/ja/activities/other/latest/workflow/uipath-testing-api-itestingservice-verifyexpression#verifyexpression(boolean%2C-string%2C-boolean%2C-string%2C-boolean%2C-boolean
:::

## 仕組みの説明
中央に定義されている配列の中身と、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/bca60758-4276-3e45-3740-8af71a6d0539.png)
（ 以降の検証シナリオに関連するため、配列の最初の **「開始」** の文字列に着目してください ）


オブジェクトリポジトリの要素名が対応しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/a701bdfc-b07b-4497-7309-12610e89e633.png)


配列をベースに繰り返しでチェックをするため、配列以外のコードを大きく変える必要はありません。

:::note
配列を手動で定義していただく点が、当手法の面倒な点です。
この点も、OCRやメモ帳などを上手く使っていただき、負荷を少なくする工夫をしていただければと思います。
:::

### その他、実装の補足説明です。

ご要件次第ではカスタマイズが必要です。

- **IsEnabled** という関数で要素が有効化であるか、をチェックしています
- 対象の要素が無い場合、上記の関数もTimeoutまで待った後に例外が発生するため **IsEnabledOptions** で **Timeout = 0** で待ち時間が発生しないようにしました
- **try-catch** ブロックで要素がある場合は例外が発生しない、要素が無い場合は例外が発生する、という形で判断しています

## 実行してみます。


#### ◆ケース１として…
ページにアクセスした直後の状態で実行を試ます。
https://rpachallenge.com/?lang=JA

#### ◆ケース２として…
左下の「開始」ボタンを押下し、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/76515442-f029-acfa-8026-9f558bcf99fa.png)

画面遷移をし意図的に **「開始」ボタン** が無い状態を再現してみます。
（「開始」ボタンが「ROUND 1」ボタンに変化します）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/0560b7c7-6c64-a8c6-1529-42ac8a838c66.png)


# 実行結果

結論としては、要素の有無を判定することに成功しました。

### ケース１：　全ての要素がある状態の出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/f1c5fd7e-f34e-47cc-cdb4-f474ce54e2a0.png)

### ケース２：　「開始」ボタンが無い状態の出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/40f855d3-7eb3-cd88-32a4-a03523af3f2f.png)


### …検証後、並列処理で高速化しました。

実は実行していて、単純なテストケースの繰り返し処理では少し遅いのが気になりました。
並列処理にすることで、処理がとても速くなりました。（15秒⇒4秒）
上に貼ったコードは並列処理にした後のものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/71b393b7-c830-1ce8-0004-9bba1e87bf9e.png)



# まとめ
個人的に想定したチェックは実現できました。
今回は実際に検証用のコードを実行して要素の有無をチェックする内容でした。
エラーが起こってから考えよう…という方針よりは、少しだけプロアクティブな対策となるのではないかと考えます。

この記事の内容は通常のワークフロー実行でも実装可能ですが、
**「オブジェクトリポジトリ」「コード化されたテストケース」** という機能により、手軽にセットアップでき、かつ再利用しやすい仕組みになっています。

:::note warn
RPA Challegeというデモサイトを想定した検証ですので、ご要件に合わせて細かいカスタマイズは必要となるであろう点にご注意ください。
:::

当手法においても、定期テストとして実行していただくとSaaS画面の変化を早期に検知できるのでは…と考えます。当記事の内容が参考になれば幸いです。