【UiPath Studio】「コード化したテストケース」と通常の「ワークフロー」を相互に呼び出す。

# はじめに

**「コード化したテストケース」** （csファイル）と **「通常のワークフロー」** （xamlファイル）のそれぞれの実装方式は、それぞれに得意なユースケースがあります。

いろいろな目的で使われることを想像すると **相互に呼び出したい…** という場面がありそうです。
これに対応する方法をまとめます。

:::note
#### 相互呼び出しが有効なユースケースの例：
- テスト実行は **コード化したテストケース** で効率的に実行しつつ、テスト失敗時のリカバリー処理は **通常のワークフロー** 処理を活用したい…！！
- 複雑な画面やExcel操作のみ **通常のワークフロー** 処理で実装したい…！！
:::


当記事に関連する内容は公式ドキュメントにも記載がありますので、応用的な利用方法などはこちらをご参照ください。

https://docs.uipath.com/ja/studio/standalone/2023.10/user-guide/creating-hybrid-automations

:::note
当記事の **「コード化したテストケース」** は **「コード化したワークフロー」** でも実行可能です。用途に合わせて読み替えてください。 
:::

## 何故この方法が必要？、それぞれの実装方法の "課題" と思われること。

当記事の前提として、以下の課題や制約があると考えました。

:::note warn
課題の内容については個人の意見です。
:::

|  | 機能概要 | 主な用途と課題 |
| --- | --- | --- |
| **ワークフロー** | 従来のワークフロー実装。 | GUI操作で実装可能で、入力メソッドの選択肢も多い。<BR>反面、再利用時も同じUIでの編集が必要。|
| **コード化したテストケース、ワークフロー** | UiPath Studio v23.10で追加されたC#で実装する機能。| 画面操作はオブジェクトリポジトリの定義が必要(＊)で、入力メソッドの選択肢が少ない。<BR>これにより、動的に変化する要素など対応しにくい要素があり得る。 |

:::note
＊ 補足：オブジェクトリポジトリが無くても下図のような実装方法はできるようです。この方法を使うためには **セレクターを文字列として把握** しておく必要がありそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/594ccc8a-99db-49ee-56a9-6a7ab589f011.png)
https://docs.uipath.com/ja/studio/standalone/2023.10/user-guide/using-imported-library-projects-in-coded-automations
:::

記載した課題のレベル感は実装者のスキルにも依存しそうです。
それぞれの実装方法に**得意・不得意 があるであろう** 、というニュアンスで捉えていただければと思います。

それでは具体的な手順を記載します。

# 通常の「ワークフロー」から **「コード化したテストケース」** を呼び出す。

このケースの手順はとても簡単です。
「ワークフロー ファイルを呼び出し」アクティビティで下図のようにcsファイルを指定するだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/d527ff95-b87e-a5ce-4026-497c0cf1572a.png)

:::note warn
デフォルトのUI操作ではcsファイルが非表示である点のみ、ご注意ください。
詳細は以下です。
:::

#### 以下の手順でcsファイルの指定が可能です。

① フォルダーマークをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/c5abb6ef-f4b7-8518-efed-49c9fbec2702.png)

② 右下の拡張子の選択子から「すべてのファイル (*.*)」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/0a70e1f6-72ea-ef2a-42cd-a7639b03e8dd.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/4bd6075f-3425-860a-9670-7bfdc6e31be9.png)
③ 表示されたcsファイルを選択します。

:::note
ファイル名、ファイルパスが分かっている場合は「ファイル名」のパラメーターに直接、文字列として入力する方法でも可能です。
:::

# **「コード化したテストケース」** から通常の「ワークフロー」を呼び出す。

こちらも手順は簡単ですが、引数と戻り値の有無で３パターン記載します。

### パターン１：　呼び出しのみ
```呼び出しだけ.cs
RunWorkflow("ワークフロー実装.xaml");
```

### パターン２：　引数あり
```引数あり.cs
RunWorkflow("ワークフロー実装.xaml"  , new Dictionary<string, object>(){
                                          { "引数名", "こちらは引数の値です" }
                                      });
```

### パターン３：　戻り値あり
```戻り値あり.cs
IDictionary<string, object> returnVal = RunWorkflow("ワークフロー実装.xaml");
// 以下のように型名を省略も可能
// var returnVal = RunWorkflow("ワークフロー実装.xaml");

// 戻り値をログ出力します
Log( "戻り値です。--->" + returnVal["戻り値"].ToString() );
```
:::note
引数と戻り値は以下の点がポイントです。
- #### 引数の型は Dictionary&lt;string, object&gt;
- #### 戻り値の型は IDictionary&lt;string, object&gt;
:::

:::note
このサンプルコードで呼び出した **ワークフローの引数の内容** は下図です。
上記コードと **引数名** （入力）と **戻り値** （出力）の名前の紐付き関係にも着目してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/6a3d4044-ecab-2bd3-313c-ce502fd68ec2.png)
:::

:::note
C#の引数、戻り値の型が **object** 型になっている点もポイントです。

どのようなクラスも設定することができますが、特に戻り値を後続処理で利用する際には実際の型に合わせて **型変換（キャスト）** が必要になります。例として、**DataTable** 型を利用する場合は以下のような書き方になります。

```cast_sample.cs
// object型をDataTable型に型変換
DataTable dt =  (DataTable) returnVal["戻り値"];
```
:::

もちろん 引数 と 戻り値 の 両方あり…というパターンも可能です。

## ※「コード化したテストケース」 から「コード化したテストケース」（csファイル）を呼び出す場合

引数と戻り値の数に応じて、少し書き方を変える必要があります。
呼び出す側と呼び出される側の例を紹介します。

### ■ 引数と戻り値が1つの場合：

こちらはxamlを呼び出す場合と変わりません。Codeフォルダのcsファイルを相対パスで呼び出す例です。

```呼び出す側.cs
var returnVal = RunWorkflow("Code\\CodedTestcase.cs"  , new Dictionary<string, object>()
                                                      {{ "引数名", "こちらは引数の値です" }} );

// ※ 気になる方は戻り値の内容も確認してみましょう。
// foreach(string s in returnVal.Keys) {                
//      Log("戻り値です。--->" + s + " : " + returnVal[s].ToString() );
// }
```

```呼び出される側_Code\\CodedTestcase.cs
[TestCase]
public string Execute(string 引数1)
{
   Log("引数--->" + 引数1);
   return "戻り値";
}
```

:::note
気になるのは、戻り値の **IDictionary** の中身ですが…
この戻り値が1件の場合のKeyは **"Output"** の文字列となっていました。

参考： 上記サンプルでコメント化したforeachで値を確認したログ出力は下図です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/18ca9fc1-0b0f-1db3-a6af-3221b82a5660.png)
:::

### ■ 引数と戻り値が複数ある場合：
```呼び出す側.cs
var returnVal = RunWorkflow("Code\\CodedTestcase.cs"  , new Dictionary<string, object>()
                                                      { { "引数1", "こちらは引数1です" },
                                                        { "引数2", 123 } }
 );

```

それぞれの変数の型を **string, int, bool** で意図的に分けてみました。
```呼び出される側_Code\\CodedTestcase.cs
[TestCase]
public ( string 戻り値1, bool 戻り値2 ) Execute(string 引数1, int 引数2)
{
    Log("引数1--->" + 引数1 + ", 引数2--->" + 引数2 );
    return ( 戻り値1: "戻り値1", 戻り値2: false );
}
```


# その他、補足情報

## ■ 補足１：　その他の実装について

実装の詳細は各ユースケースの要件ごとに異なると考えられます。
例として、処理の途中で実行ワークフローを切り替える際などは、**オープン動作をIfNotOpen** に設定する等をお試しください。

##### 通常のワークフローのオープン動作：IfNotOpen
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/d66416eb-d84b-9238-8edf-f21f1b2ece58.png)
##### コード化したテストケースのオープン動作：IfNotOpen
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/52ab8c00-d313-d8f6-8930-f4c445c5d3a8.png)

## ■ 補足２：　Execute関数のオーバーロードはNGです。

C#の仕様としては、同名関数で異なる引数（オーバーロード）が可能で、UiPath Studioの見た目上でもエラーとなりません。
ただし実行を試みると **UiPath Studioとしてのコンパイルエラー** となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/5ae9164c-5784-8f35-76c5-384d35941017.png)

通常は遭遇しにくいと思いますが、古い関数を残してTry＆Error検証する場合などは注意が必要です。

## ■ 補足３：　引数の不一致は以下のエラーが表示されます。

呼び出し側で指定した引数名が、呼び出された側に不足している場合（つまり引数の名前が一致しない場合）、下図のエラーが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/b5a37df0-c090-75c0-61c5-4a1c66f2739b.png)

ただし、下図のようなケース、呼び出し側で引数が不足している場合は実行可能です。
（つまり **引数名に不一致が無い状態** では実行可能であるようです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/28604d69-b82a-6209-4f75-9c58188c27a9.png)


# まとめ
「コード化したテストケース」 と 「通常のワークフロー」 をそれぞれ相互に呼び出す方法をまとめました。
こういったハイブリッド的な活用がより生産性を高める可能性を秘めているように感じます。
当機能を活用される際に参考になれば幸いです。