30秒ではじめる作業自動化・UIテスト自動化

この記事は[ニフクラ](https://www.nifcloud.com/) 等を提供している、[富士通クラウドテクノロジーズ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/fjct) の12日目の記事です。

前日は@ks2022さんの[チームで障害訓練をした話](https://qiita.com/ks2022/items/8fc311bb52b6c6c3321c)でした。

障害対応はチームメンバー誰もができることが望ましいですが、事前に学習しておくことも難しく、障害対応をするまではハードルが高いものだと感じていました。
障害訓練で一度経験しておくことで、障害発生時にも過度な不安や緊張が起こらず対応できそうだなと感じました。
記事を参考に私のチームでも取り入れたいです💪。


## はじめに
「このポチポチする作業、自動化できないかな」ってことありますよね。
「UIテストを自動化して手間を減らしたいけど難しそう」、「今更自動化に多くの時間をかけたくない」ということもあるかもしれません。

そんな人におすすめなのが「Katalon Recorder」です。
30秒で利用できます。

~~といったもののまだ何度か使った程度なのでお手柔らかにお願いします。
この機会に勉強します。~~

## Katalon Recorderとは
手軽にUIテストが自動化できるソフトウェア「Katalon Studio」をブラウザの拡張機能としてもっと手軽に使用できるようにしたものです。

Katalon Studioについては以下の記事が分かりやすかったので紹介しておきます。

https://qiita.com/kazurayam/items/aece5d314f84893a0a14


似たソフトウェアだと「Selenium IDE」というものがありますが、Katalon Recorderの方が**短期間で価値を実現できる**とアピールされていました。


https://docs.katalon.com/docs/legacy/katalon-recorder/production-evaluation-center/katalon-recorder-vs-selenium-ide

## 始め方
1. ブラウザの拡張機能として追加
[Chrome](https://chrome.google.com/webstore/detail/katalon-recorder-selenium/ljdobmomdgdljniojadhoplhkpialdid?hl=ja) 
[edge](https://microsoftedge.microsoft.com/addons/detail/katalon-recorder-seleniu/hdodkejagjkdomgbiioijegfmiiknoam) 
[firefox](https://addons.mozilla.org/ja/firefox/addon/katalon-automation-record/)

1. ブラウザの拡張機能欄から「Katalon Recorder」をクリックして起動

はい、30秒で始められました。
あとは「Record」をクリックしてブラウザで自動化したい作業を行うだけです。

まずはユーザ登録不要のChrome版を使うことをおすすめします。
※edgeとfirefoxではユーザ登録していないとテストケースを2個しか作成できません。


## さっそくやってみる
### gmailを開いてメールを送信する
1. Katalon Recorderの「Record」クリック
1. gmailを開く
1. 「作成」をクリック
1. 「宛先」を入力
1. 「件名」を入力
1. 「本文」を入力
1. 「送信」をクリック
1. Katalon Recorderの「Stop」クリック

とするとKatalon Recorderには以下のように記憶されました。

|Command|Target|Value|
|--|--|--|
|open|https://mail.google.com/mail/u/0/?tab=rm&ogbl||
|click|xpath=(.//*[normalize-space(text()) and normalize-space(.)='検索'])[1]/following::div[38]||
|click|xpath=(.//*[normalize-space(text()) and normalize-space(.)='Google にフィードバックを送信'])[1]/following::div[35]||
|type|id=:tq|hoge@hogehoge.com|
|click|id=:pt||
|type|id=:pt|katalontest|
|click|id=:r0||
|editContent|id=:r0|testmail|
|click|id=:pj||

Katalon Recorder上部の「Play Test Case」をクリックすると記録した操作が実行されます。
※テストケースの実行前にKatalon Recorderの設定から「Speed」を真ん中あたりにしておくことをおすすめします。

これで簡単にブラウザ操作を自動化できました。

また、TargetとValueをみると id=:tqが宛先、id=:ptが件名、id=:r0が本文を指していることが分かります。
Katalon Recoder上からValueを変更するだけで宛先や件名、本文を変えてメール送信することができます。

これで効率が上がったかというと微妙ですし、こんな作業を自動化したところであまり意味はありません。

Katalon Recorderにはまだまだ機能があります。
- ifを使って分岐処理をする
- whileを使って繰り返し処理をする
- 変数にcsvから値を読みとった値を入れる
- テストの証拠としてスクリーンショットをする


## 自動化するうえで知っておくべきコマンド・機能

* コマンドリファレンス

https://docs.katalon.com/docs/legacy/katalon-recorder/get-your-job-done/automate-scenarios/selenese-selenium-ide-commands-reference

* Selenium IDE互換なので以下もとても参考になりました。

https://qiita.com/oh_rusty_nail/items/77782973b4152992017b

### 使用例

#### 変数を使う
**store**コマンドを使います。
変数はValue, 値はTargetにいれます。
typeコマンドなどで ${変数名} で使用できます。
先ほどのgmailの例だと以下のようにできます。

|Command|Target|Value|
|--|--|--|
|store|hoge@hogehoge.com|toaddress|
|type|id=:tq|${toaddress}|

#### 変数や値をcsv, jsonで設定する
**loadVars, endloadVars**コマンドを使います。
**Katalon Recorder から「Test Data」->「Open a Data File」** をクリックして対象のcsvかjsonを選択します。
対象のファイルを選択して、「Use this in a test case」を押すとダイアログが表示され、1ページ目では使用するテストケースを選択、2ページ目ではテストケース内のValueをcsv内の変数に置き換えることができます。
Addをクリックすることで反映され、テストケースの先頭にloadVarsコマンド、末尾にendLoadVarsコマンドが追加され、その間で繰り返し処理となります。

先ほどのgmailの例だと以下のようにできます。
※csvは1行目が変数名となります。
```import.csv
toaddress,subject,body
hoge@hogehoge.com,test,katalon
piyo@hogehoge.com,test,katalon
```
```import.json
[
  {
    "toaddress":"hoge@hogehoge.com",
    "subject":"test",
    "body":"katalon"
  },
  {  "toaddress":"piyo@hogehoge.com",
     "subject":"test",
     "body":"katalon"
  }
]
```

|Command|Target|Value|
|--|--|--|
|loadVars|||
|type|id=:tq|${toaddress}|
|endloadVars|||

#### 分岐処理をする
**if, else if, else, endif**コマンドを使います。
store系コマンド(store)などと合わせて使うことでブラウザの表示に合わせた処理ができます。
storeText, storeTitleなどはTargetに変数名をいれるようでした。
if, endIfのTargetには条件を入力します。

「ブラウザの現在のページがqiitaの富士通クラウドテクノロジーズのアドベントカレンダー2022であれば一日目の記事をクリック、他のページをみている場合は富士通クラウドテクノロジーズのアドベントカレンダーにアクセスする」 という操作だと以下のようになります。

|Command|Target|Value|
|--|--|--|
|storeTitle|title||
|if|"${title}"=="富士通クラウドテクノロジーズのカレンダー \| Advent Calendar 2022 - Qiita"||
|click|link=パケットキャプチャからKubernetes APIのTLS通信を解析する||
|else|||
|open|https://qiita.com/advent-calendar/2022/fjct||
|endIf|


#### 繰り返し処理をする
**while, endWhile**コマンドを使います。
store, storeEvalコマンドなどと合わせて使います。
whileのTargetには条件を入力します。
「Yahoo天気で5日間分の天気をみる」という操作だと以下のようになります。
|Command|Target|Value|
|--|--|--|
|store|1|day|
|while|${day}<=5||
|open|https://weather.yahoo.co.jp/weather/?day=${day}||
|storeEval|${day}+1|day|
|endWhile||

#### screenshotをする
**captureEntirePageScreenshot**コマンドを使います。
Targetにファイル名を指定できます。空白の場合はファイル名は実行時の時間.pngとなります。
KatalonRecoderの下のScreenshotsから確認できます。
|Command|Target|Value|
|--|--|--|
|captureEntirePageScreenshot|test.png||

#### JavaScriptを使用する
**runscript**コマンドを使用します。
TargetにJavaScriptを記載し動かすことができます。
returnによって変数に値をいれることもできます。
対象のテストステップを右クリックしてできる「Play this test step」を活用することで動作確認がしやすいです。
テスト内でテスト実行日を使用したい場合は以下のようにできます。
 
|Command|Target|Value|
|--|--|--|
|runScript|var date = new Date(); var today = date.getFullYear() + '/' + date.getMonth() + '/' +date.getDate(); return today;|today|

Katalon Recorder下部のLogからもJavascriptの実行結果が確認できます。
```
[info] Executing: | runScript | var date = new Date(); var today = date.getFullYear() + '/' + date.getMonth() + '/' +date.getDate(); return today; | today |
[info] Store '2022/11/10' into 'today'
```
  
#### assert|verify
値の検証に使用します。
Selenium IDEではassertの場合は異常があった場合テストが途中で終了、verifyの場合は異常があってもテストを続けるとの記載がありますが、Katalon Recorderではassertもverifyも異常時は止まるようでどちらを使っても良さそうです。
異常終了時には画面がスクリーンショットされます。
asserthoge, verifyhogeのTargetには正常時に期待する値を入力します。

「ブラウザの現在のページがqiitaの富士通クラウドテクノロジーズのアドベントカレンダー2022である」ことを検証したい場合は以下のようになります。
|Command|Target|Value|
|--|--|--|
|assertTitle|富士通クラウドテクノロジーズのカレンダー \| Advent Calendar 2022 - Qiita|
```
正常時のログ
[info] Executing: | assertTitle | 富士通クラウドテクノロジーズのカレンダー | Advent Calendar 2022 - Qiita | |

異常時のログ
[info] Executing: | assertTitle | 富士通クラウドテクノロジーズのカレンダー | Advent Calendar 2022 - Qiita | |
[error] Actual value 'ニフクラ[NIFCLOUD] / クラウドと共に世の中を「新しい未来」へ' did not match '富士通クラウドテクノロジーズのカレンダー | Advent Calendar 2022 - Qiita'
[info] Pausing

```
ブラウザの現在のページがTargetと違った場合はエラーが起こり、テストが中断されます。

#### テストのインポート、エクスポート
テストスイートをインポート、エクスポートすることができます。
chromeの場合は対象のテストスイートを右クリックして、「Download test suite」からエクスポート、「Open Test Suite」からインポートできます。
firefox, edgeの場合は対象のテストスイートを右クリックして、「Save Test Suite to Computer」からエクスポート、「Open Test Suites」からインポートできます。
chromeでテストを作成してエクスポート、firefoxでインポートしテスト実行 とすることでクロスブラウザでテストすることができます。


## 実際にUIテストっぽくやってみる
* Katalon Recorder用の[デモページ](https://docs.katalon.com/docs/legacy/katalon-studio-enterprise/get-started/sample-projects/sample-projects-overview) が公開されていますので、そちらを使ってやっていきます。
* 以下のページでログインやメニューバーのテストをしてみます。
  * https://katalon-demo-cura.herokuapp.com/

### やること
* ID, PASSWORDをグローバル変数として使用
  * ProfilesにID, PASSWORDを追加（csv, jsonのインポートと同じようなやり方）


* ログイン機能のテスト
1. 誤ったID, PASSWORDでログインしようとした場合にエラーが表示される
1. スクリーンショット
1. 正常なID, PASSWORDでログインした場合に予約ページが表記される
1. スクリーンショット

テストケース
|Command|Target|Value|
|--|--|--|
|open|https://katalon-demo-cura.herokuapp.com/|
|click|id=btn-make-appointment||
|type|id=txt-username|John Do||
|type|id=txt-password|THISISNOTAPASSWORD|
|click|id=btn-login||
|verifyText|xpath=//section[@id='login']/div/div/div/p[2]|Login failed! Please ensure the username and password are valid.|
|captureEntirePageScreenshot|||
|type|id=txt-username|${GlobalVariable.ID}|
|type|id=txt-password|${GlobalVariable.PASSWORD}|
|click|id=btn-login||
|verifyTitle|CURA Healthcare Service||
|captureEntirePageScreenshot||

ログ
```
[info] Executing: | open | https://katalon-demo-cura.herokuapp.com/ | |
[info] Executing: | click | id=btn-make-appointment | |
[info] Executing: | type | id=txt-username | John Do |
[info] Executing: | type | id=txt-password | THISISNOTAPASSWORD |
[info] Executing: | click | id=btn-login | |
[info] Executing: | verifyText | xpath=//section[@id='login']/div/div/div/p[2] | Login failed! Please ensure the username and password are valid. |
[info] Executing: | captureEntirePageScreenshot | | |

[info] Executing: | type | id=txt-username | ${GlobalVariable.ID} |
[info] Expand variable '${GlobalVariable.ID}' into 'John Doe'
[info] Executing: | type | id=txt-password | ${GlobalVariable.PASSWORD} |
[info] Expand variable '${GlobalVariable.PASSWORD}' into 'ThisIsNotAPassword'
[info] Executing: | click | id=btn-login | |
[info] Executing: | verifyTitle | CURA Healthcare Service | |
[info] Executing: | captureEntirePageScreenshot | | |

[info] Test case passed
```

スクリーンショット
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2250956/6d51524b-0afa-2e49-f733-5c55ca28c05b.png width=800px>


<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2250956/4932c751-5123-b3cd-da2c-db02b0590505.png width=800px>



* メニューバーのテスト
1. ログイン前にメニューバーをクリックすると「Home」と「Login」が表示される
1. 「Login」をクリックするとログインページに移動する
1. 「Home」をクリックするとホームに移動する
1. メニューバーを表示させる
1. スクリーンショットをとる
1. 正常なID, PASSWORDでログインした場合に予約ページが表記される
1. メニューバーを表示させる
1. スクリーンショットをとる
1. ログイン後のメニューバーに「Home」「history」「Profile」「Logout」が表示される
1. 「Home」をクリックするとホームに移動する
1. 「history」をクリックするとヒストリーページに移動する
1. 「Profile」をクリックするとプロフィールページに移動する
1. 「Logout」をクリックするとログアウトされ、ログイン前のホームに移動する

テストケース
|Command|Target|Value|
|--|--|--|
|open|https://katalon-demo-cura.herokuapp.com/||
|click|xpath=//a[@id='menu-toggle']/i||
|click|link=Login||
|verifyText|xpath=//section[@id='login']/div/div/div/h2|Login|
|click|id=menu-toggle||
|click|link=Home||
|click|id=btn-make-appointment||	
|click|id=menu-toggle||
|captureEntirePageScreenshot||		
|verifyText|link=Home||Home|
|verifyText|link=Login|Login|
|type|id=txt-username|${GlobalVariable.ID}|
|type|id=txt-password|${GlobalVariable.PASSWORD}|
|click|id=btn-login||
|click|id=menu-toggle||
|captureEntirePageScreenshot||		
|verifyText|link=Home|Home|
|verifyText|link=History|History|
|verifyText|link=Profile|Profile|
|verifyText|link=Logout|Logout|
|click|id=menu-toggle||
|click|link=Home||
|verifyTitle|CURA Healthcare Service||
|click|id=menu-toggle||
|click|link=History||
|verifyText|xpath=//section[@id='history']/div/div/div/h2|History|
|click|xpath=//a[@id='menu-toggle']/i||
|click|link=Profile||
|verifyText|xpath=//section[@id='profile']/div/div/div/h2|Profile|
|click|link=Logout|
|verifyTitle|CURA Healthcare Service|

ログ
```
[info] Executing: | open | https://katalon-demo-cura.herokuapp.com/ | |
[info] Executing: | click | xpath=//a[@id='menu-toggle']/i | |
[info] Executing: | click | link=Login | |
[info] Executing: | verifyText | xpath=//section[@id='login']/div/div/div/h2 | Login |
[info] Executing: | click | id=menu-toggle | |
[info] Executing: | click | link=Home | |
[info] Executing: | click | id=btn-make-appointment | |
[info] Executing: | click | id=menu-toggle | |
[info] Executing: | captureEntirePageScreenshot | | |

[info] Executing: | verifyText | link=Home | Home |
[info] Executing: | verifyText | link=Login | Login |
[info] Executing: | type | id=txt-username | ${GlobalVariable.ID} |
[info] Expand variable '${GlobalVariable.ID}' into 'John Doe'
[info] Executing: | type | id=txt-password | ${GlobalVariable.PASSWORD} |
[info] Expand variable '${GlobalVariable.PASSWORD}' into 'ThisIsNotAPassword'
[info] Executing: | click | id=btn-login | |
[info] Executing: | click | id=menu-toggle | |
[info] Executing: | captureEntirePageScreenshot | | |

[info] Executing: | verifyText | link=Home | Home |
[info] Executing: | verifyText | link=History | History |
[info] Executing: | verifyText | link=Profile | Profile |
[info] Executing: | verifyText | link=Logout | Logout |
[info] Executing: | click | id=menu-toggle | |
[info] Executing: | click | link=Home | |
[info] Executing: | verifyTitle | CURA Healthcare Service | |
[info] Executing: | click | id=menu-toggle | |
[info] Executing: | click | link=History | |
[info] Executing: | verifyText | xpath=//section[@id='history']/div/div/div/h2 | History |
[info] Executing: | click | xpath=//a[@id='menu-toggle']/i | |
[info] Executing: | click | link=Profile | |
[info] Executing: | verifyText | xpath=//section[@id='profile']/div/div/div/h2 | Profile |
[info] Executing: | click | link=Logout | |
[info] Executing: | verifyTitle | CURA Healthcare Service | |
[info] Test case passed
```

スクリーンショット
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2250956/47fcbd30-b958-1eb1-e407-35feaf9670e2.png width=800px>

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2250956/645f10bb-b078-4f8e-27bc-1f949189db25.png width=800px>




## おわりに
今回はKatalon Recorderのいくつかの機能について触ってみてデモページで自動テストを行ってみました。
テスト操作を再現するだけで自動化することができ、テストケースの修正も少し手を加えるだけでできました。
今回はデモページでしたが、今後は実際のテストを自動化していきたいです💪。

現状はKatalon Recorderでテスト開始をクリックしていますが、CIに組み込んだりできないかも試してみたいです。
いつかの記事をお楽しみに👋。



この記事は[富士通クラウドテクノロジーズ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/fjct) の12日目の記事でした。
明日は@George22eさんの「たぶんヴァイオリン演奏に関する何か」です。

技術×音楽なんでしょうか？一体どんな内容なのか楽しみです。
明日の記事もお楽しみに👋。