Katalon Studioでテストを自作した（２）

# はじめに

わたしはWebアプリケーションのUIをテストする作業をソフトウェアで自動化する技術に関心があります。2018年1月以来わたしは [Katalon Studio](https://www.katalon.com/) というソフトウェアに注目しています。以前[「Katalon Studioとはどんなソフトウエアか」](https://qiita.com/kazurayam/items/aece5d314f84893a0a14#_reference-ddacffec3e84567a0caa)で概要を紹介しました。[前回](https://qiita.com/kazurayam/items/bdf71ed70fdc32bb1758)はRecord機能を使って自動生成したコードを手直しして自動化テストと呼べる内容のKatalon Studioプロジェクトを作りました。

あなたのWebサイトが大規模であればそれに比例して自動化テストも大きくならざるをえません。前回作った [CURA-Test-Project](https://github.com/kazurayam/CURA-Test-Project/tree/step7) をそのまま大きくすると、あちこちでコードが重複し読みにくく理解しにくいプロジェクトになるでしょう。今回は CURA-Test-Project を更に手直ししながら、Katalon Studioプロジェクトを大規模なWebサイトに対応可能にするテクニックを紹介します。

# 前提条件
- Katalon StudioはWindows、Linuxでも利用可能ですが、今回の記事を書くにあたっては macOS High Siera 10.16 , Katalon Studio 5.4.1で検証しました。
- Katalon Studioのインストールについては[「Katalon Studioをインストールした」](https://qiita.com/kazurayam/items/135cb30233d11c2f4840#_reference-a84912a2daa04759e1aa0)を参考に

# サンプル in GitHub

この記事が説明するKatalon Projectのファイル一式をGitHubにアップしました。

- https://github.com/kazurayam/CURA-Test-Project

このレポジトリのmasterブランチをローカルにcloneする操作はコマンドラインでこうします。

```
$ cd ~
$ mkdir katalon-workspace
$ cd katalon-workspace
$ git clone https://github.com/kazurayam/CURA-Test-Project.git
```

このレポジトリにはmasterプランチだけでなく、途中経過を保存したブランチがいくつかあります。 

| ブランチ名 | 内容 |
|:-----:|:-------|
| step0 | Record機能を使って自動生成したばかり。リファクタリングする前。verification無し。Runすれば成功する |
| step1 | Object Repositoryにページ毎サブフォルダ4つを追加し、Test Object群を配置し直した。Test Objectの名前はもとのまま |
| step2 | Test Objectの名前を見直した |
| step3 | Test Objectのselectorを見直した |
| step4 | 不要なTest Objectを削除した |
| step5 | ページ遷移のチェックを実装した |
| step6 | データのチェックを実装した |
| step7 | わざとverifyEqualがFAILするようにした、LogViewerの表示を確認するため |

以上のブランチについては[前回](https://qiita.com/kazurayam/items/bdf71ed70fdc32bb1758)の記事が説明しています。今回の記事に対応するブランチは以下のとおりです。

| ブランチ名 | 内容 |
|:-----:|:-------|
| step8 | Test Caseのモジュール化。`Common/Login`を追加|
| step9 | GlobalVariableを導入した |
| step10 | Execution Profileで複数環境をテスト対象にする |
| step11 | Test Suiteを導入した |
| master | 最終形 |

リモートのstep7をローカルにcloneするには下記の操作をします。

```
$ git checkout -b stepy origin/step7 
```


# Test Caseのモジュール化

step7ブランチのCURA-Test-ProjectにはTest Caseがひとつだけありました。すなわち [`Basic`](https://github.com/kazurayam/CURA-Test-Project/blob/step7/Scripts/Basic/Script1525154068917.groovy)です。Katalon StudioではTest Caseを１つしか作ることができないのでしょうか？そんなことはありません。Katalon Studioでは複数のTest Caseを作ることができます。例えばテスト対象のWebサイトが下記のように複数のURLから構成されているなら、そのURLごとにTest Caseを作るのが自然でしょう。

- https://www.katalon.com/katalon-studio/
- https://www.katalon.com/katalon-analytics/
- https://www.katalon.com/resources-center/blog/katalon-automation-recorder/

しかし複数のTest Caseを作り始めるとすぐ、複数のTest Caseに同じコードが重複して現れることに気づくでしょう。コードの重複を可能な限り少なくすることはプログラミングの基本です。Test Caseに生じたコードの重複部分を括り出してモジュール化すべきです。

Katalon Studioではモジュール化すべきコードをひとつの Test Case にします。そしてモジュールとしてのTest Caseを他のTest Caseが呼び出すことができます。具体的には [WebUI.callTestCase()](https://docs.katalon.com/display/KD/Call+test+case) キーワードを使います。

step8のCURA-Test-Projectでモジュール化のサンプルを示しています。step7のTest Case `Basic` からログイン処理を括り出して別のTest Case `Login` を作りました。そして `Basic` が `Login` をcallする形に変更しました。同時に `Basic` が `Login` をcallするときにUsernameとPasswordをパラメータとして指定する形にしました。図にすると下記のような形です。

![TestCase_calls_TestCase.png](https://qiita-image-store.s3.amazonaws.com/0/52995/926f25f8-e0b9-e545-ac2e-47ab240a194d.png)

なおサブフォルダを作ってTest Caseをグループに分類することができます。任意の名前のサブフォルダをいくつでも作ることができます。フォルダ名を工夫することによりTest Case群を性質によって分類して理解しやすくすることができます。step8でCommonフォルダとMainフォルダを導入しました。

- `Common/Login`
- `Main/Basic`

呼び出す側のTest Case [`Main/Basic`](https://github.com/kazurayam/CURA-Test-Project/blob/step8/Scripts/Main/Basic/Script1525154068917.groovy) のGroovyコードは下記のようになりました。

```
// Make AppointmentボタンをクリックしてLogin画面を呼び出しUsernameとPasswordを入力しログインするまでを
// 別のTest Caseで実行する
WebUI.callTestCase(findTestCase('Common/Login'),
	[
		'Username': 'John Doe',
		'Password': 'ThisIsNotAPassword'
	],
	FailureHandling.STOP_ON_FAILURE)
```

呼び出される側のTest Case [`Common/Login`](https://github.com/kazurayam/CURA-Test-Project/blob/step8/Scripts/Common/Login/Script1526203923621.groovy) のGroovyコードは下記のようになりました。

```
WebUI.click(findTestObject('Page_CuraHomepage/a_Make Appointment'))
// ここでログイン・ページに遷移
WebUI.verifyElementPresent(findTestObject('Page_Login/button_Login'),
	10, FailureHandling.STOP_ON_FAILURE)

WebUI.setText(findTestObject('Page_Login/input_username'), Username)
WebUI.setText(findTestObject('Page_Login/input_password'), Password)

WebUI.click(findTestObject('Page_Login/button_Login'))
// ここで入力ページに遷移
WebUI.verifyElementPresent(findTestObject('Page_CuraAppointment/button_Book Appointment'),
	10, FailureHandling.STOP_ON_FAILURE)
```

## parameters

Callされる側である `Common/Login`のスクリプトが `Username` と `Password` という名前の変数を参照している点に注目しましょう。この二つの変数の宣言がスクリプトの中には見当たりません。どこで変数を宣言するのでしょうか？

じつはTest Case `Common/Login` をGUIで開いたときに Manualタブ、Scriptタブの次に Variables タブがあります。VariablesタブのなかにcallTestCaseキーワードで渡されたパラメータ値を引き受けるための変数名と変数型を宣言します。次のスクリーンショットを参照のこと。
![スクリーンショット 2018-05-13 20.13.51.png](https://qiita-image-store.s3.amazonaws.com/0/52995/1711728f-4296-2ca7-a496-20e8ae7024ad.png)

なお公式ドキュメント [Variable Types](https://docs.katalon.com/display/KD/Variable+Types) に変数のタイプにかんする説明が書いてあるのですが残念ながらその記述はいまいちの出来です。

## step8

この段階をGitHub上のCURA-Testing-Projectのstep8ブランチとして保存しました。step8ブランチをローカルに取り出すには下記の操作をします。

```
$ cd ~/katalon-workspace/CURA-Test-Project
$ git checkout -b step5 origin/step8
```
 
# 定数値をGlobalVariableとして記述する

Test Caseが定数値を参照するのはよくあるはなしです。たとえば

| 定数値 | 意味 |
|:------|:--------|
| `http://demoaut.katalon.com` |ホスト名ないしはURLのprefix部分 | 
| `John Doe` | ログインするのに必要なUsername | 
| `ThisIsNotAPassword` |ログインするのに必要なPassword |

これら定数値をTest Caseのあちこちに繰り返し書くのは良くありません。あとで値を変更したくなったときに探し回らなければならなくなるから。定数値を一箇所にだけ書くことにしたい。どうすればいいか？

こうします。

1. Katalon Studioの画面左のTests Explorerペインのなかに [`Profile`](https://docs.katalon.com/pages/viewpage.action?pageId=13697476) というモノがある。Profileのなかに `default` という入れ物がある。
2. defaultプロファイルのなかに Username と Password を宣言する。Execution Profileに宣言された変数は[GlobalVariable](https://docs.katalon.com/display/KD/Variable+Types)すなわちグローバル変数となる。Excution Profiles/defaultのUsernameとPasswordに初期値を設定することができる。
1. Test CaseのスクリプトがGlobalVariableを参照するようにTest Caseを書く
1. Test Caseを実行するときにはExceution Profileのなかからプロファイルをひとつ選択して実行する。

![Profiles(GlobalVariables).png](https://qiita-image-store.s3.amazonaws.com/0/52995/78d5dd8c-51fd-754c-ea6c-50254b429bdc.png)

上記リストの3.すなわちTest Case `Basic` がGlobalVariableのUsernameとPasswordを参照している箇所は下記のようなコードになりました:

```
...

import internal.GlobalVariable as GlobalVariable

...

// Make AppointmentボタンをクリックしてLogin画面を呼び出しUsernameとPasswordを入力しログインするまでを
// 別のTest Caseで実行する
WebUI.callTestCase(findTestCase('Common/Login'),
	[
		'Username': GlobalVariable.Username,
		'Password': GlobalVariable.Password
	],
	FailureHandling.STOP_ON_FAILURE)
```
`internal.GlobalVariable`というクラスをimportする必要があります。ただし

```
import internal.GlobalVariable as GlobalVariable
```

という一行はTest Caseを新規に作成したときにKatalon Studioによって自動的に作成されます。もしもこのimport文が無くなっていたら追記しましょう。

GlobalVariableを導入することにより `John Doe` という定数値をTest Caseのスクリプトのなかに書くかわりに `GlobalVariable.Username` という変数名を書けるようになりました。変数の初期値を設定しているのはProfile/defaultプロファイル1箇所ですから、あとで初期値を変更するのは容易です。

## GlobalVariableがどのように実装されているか

グローバル変数である Username をTest Caseが参照するために `GlobalVariable.Username` と記述するのですが、Groovy言語の構文の観点からみてこれが何を意味するのでしょうか？それはこうです。

1. クラス `internal.GlobalVariable` が存在していてKatalon Studio実行時のクラスパスにより参照可能になっている
2. `internal.GlobalVariable`クラスがstaticなメンバー変数 Username を持っている。
3. GUIのProfileで指定された初期値によって Username 変数が初期化されている。

実際にこのとおりに実装されたGroovyコードがKatalon Studioによってプロジェクトのなかに動的に生成されています。

`%CURA-Test-Project%/Libs/internal/GlobalVariable.groovy` 

```
package internal

import com.kms.katalon.core.configuration.RunConfiguration
import com.kms.katalon.core.testobject.ObjectRepository as ObjectRepository
import com.kms.katalon.core.testdata.TestDataFactory as TestDataFactory
import com.kms.katalon.core.testcase.TestCaseFactory as TestCaseFactory
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase

/**
 * This class is generated automatically by Katalon Studio and should not be modified or deleted.
 */
public class GlobalVariable {
    public static Object Username     
    public static Object Password     
    public static Object Hostname
    static {
        def allVariables = [:]        
        allVariables.put('default', ['Username' : 'John Doe', 'Password' : 'ThisIsNotAPassword', 'Hostname' : 'demoaut.katalon.com'])
        allVariables.put('develop', allVariables['default'] + ['Hostname' : 'demoaut-mimic.kazurayam.com', 'Username' : 'foo', 'Password' : 'bar'])
        allVariables.put('product', allVariables['default'] + ['Hostname' : 'demoaut.katalon.com', 'Username' : 'John Doe', 'Password' : 'ThisIsNotAPassword'])
        allVariables.put('staging', allVariables['default'] + ['Hostname' : 'demoaut-staging.katalon.com', 'Username' : 'who knows', 'Password' : 'DK2mai7qli9ZS'])        
        String profileName = RunConfiguration.getExecutionProfile()        
        def selectedVariables = allVariables[profileName]
        Username = selectedVariables['Username']
        Password = selectedVariables['Password']
        Hostname = selectedVariables['Hostname']        
    }
}
```
これがGlobalVariableの実体です。わかってしまえば不思議なところはありません。

## step9

この段階をGitHub上のCURA-Testing-Projectのstep9ブランチとして保存しました。step9ブランチをローカルに取り出すには下記の操作をします。

```
$ cd ~/katalon-workspace/CURA-Test-Project
$ git checkout -b step9 origin/step9
``` 

# Execution Profileでテスト対象を切り替える

ひとつのWebアプリケーションのために複数の環境（開発環境＋ステージング環境＋本番環境とか）があるのはごく普通のことです。各環境にはきっと固有のホスト名があるでしょう。UsernameとPasswordも環境ごとに違っているかもしれません。いまKatalon Studioでテスト・プロジェクトをひとつ作成し複数環境に適用したい。ただし環境を切り替えるためにその都度ソースコードを手で書き直さなければならないのは嫌だ。こういう場合、どうすればいいか？

[Execution Profile](https://docs.katalon.com/pages/viewpage.action?pageId=13697476)を利用すればひとつのテスト・プロジェクトを複数の環境に適用することができます。

Katalon Studioのウインドウの左サイドバーのTests Explorerの最下部に Profiles があり、その中にはdefaultというプロファイルがあります。ここにカスタムなプロファイルを複数追加することができます。`develop`、`product`、`staging`、という3つのプロファイルを追加しましょう。

| Profile名 | GlobalVariable名 | 初期値 |
|:--------|:---------|:----------------------------|
| develop | Hostname | demoaut-mimic.kazurayam.com |
| develop | Useraname | foo |
| develop | Password | bar |

| Profile名 | GlobalVariable名 | 初期値 |
|:--------|:---------|:----------------------------|
| product | Hostname | demoaut.katalon.com |
| product | Username | John Doe |
| product | Password | ThisIsNotAPassword |

| Profile名 | GlobalVariable名 | 初期値 |
|:--------|:---------|:----------------------------|
| staging | Hostname | demoaut-staging.katalon.com |
| staging | Username | who knows |
| staging | Password | DK2mai7qli9ZS |

Katalon StudioのGUIのどこでProfileを追加するかというと下記スクリーンショットのとおり。
![more_profiles.png](https://qiita-image-store.s3.amazonaws.com/0/52995/9d520f7c-e143-7173-1310-0fb278e19b9b.png)

ここまで準備ができたところで、GUIの右上にあるボタンをクリックしてProfileを選択します。選択されたProfileに登録されたGlobalVariableの初期値がTest Case実行時に参照されます。

![selecting_a_profile_to_execute_with.PNG](https://qiita-image-store.s3.amazonaws.com/0/52995/f0966d5b-c076-94d0-4553-ecf044228978.png)

本番環境をテストするにはGUI右上のドロップダウンリストで `product` を選択することにより `GlobalVariable.Hostname` の初期値として `demoaut.katalon.com` が設定されます。開発環境をテストするには `develop` を選択し、ステージング環境をテストするには `staging` を選択すれよい。このようにしてテスト対象としての環境を切り替えることが容易に可能です。

## step10

この段階をGitHub上のCURA-Testing-Projectのstep10ブランチとして保存しました。step10ブランチをローカルに取り出すには下記の操作をします。

```
$ cd ~/katalon-workspace/CURA-Test-Project
$ git checkout -b step10 origin/step10
``` 

# 複数のTest Casesを一括実行する：Test Suite

ここまでCURA-Test-ProjectにはTest Caseが`Basic`ひとつあるだけでした。ここで `LoginTest` を追加しましょう。`LoginTest`はトップページを開いてログインできるかどうかをテストするだけで診察予約の入力のことは省いたシンプルなテストであるとします。

さてわたしは `LoginTest`と`Basic`をまとめて実行したい。`LoginTest`をRunするために1回ボタンを押し、`Basic`をRunするためにもう1回ボタンを押すのは面倒くさい。1回のRun操作で2つ以上複数個のTest Casesを一括して実行したい。こんごTest Casetが10個、50個、100個と増えても1回の操作でまとめて実行したい。どうすればいいか？

そんな要求を実現するために [Test Suite](https://docs.katalon.com/display/KD/Execute+a+test+suite) があります。

下記スクリーンショットが示すように Test Suite `TS1` を作りました。`TS1`は2つのTest Caseを単純に列挙したもので、Test Suite `TS1` を実行することによって間接的に2つのTest Caseが上から下に順番に実行されます。
![TestSuites_TS1.png](https://qiita-image-store.s3.amazonaws.com/0/52995/605ae733-303f-a7b7-3092-dbce670836f3.png)

ひとつのTest Suiteの配下に登録できるTest Caseの数には上限がありません。わたしが試したことがあるのはせいぜい10個程度ですが、[Katalon Forum](https://forum.katalon.com/discussion/6748/katalon-studio-is-taking-too-long-to-add-test-cases-to-test-suite#latest)によれば500個のTest CaseをひとつのTest Suiteで一括実行するという剛の者もいるようです。

Test SuiteをRunするには下記のように操作します。Test CaseひとつをRunするのと同じ操作です。

1. Tests ExplorerでTest Suite `TS1` をダブルクリックする。すると`TS1`がKatalon Studioによりロードされる。
2. ウインドウ右上にあるRunボタンでブラウザを選択して実行する

![run_testsuite.png](https://qiita-image-store.s3.amazonaws.com/0/52995/544570ae-956d-f930-2684-f767360ea15a.png)

## step11

この段階をGitHub上のCURA-Testing-Projectのstep11ブランチとして保存しました。step11ブランチをローカルに取り出すには下記の操作をします。

```
$ cd ~/katalon-workspace/CURA-Test-Project
$ git checkout -b step11 origin/step11
``` 

# ReportsでTest Suiteの実行結果をみる

Test Caseの実行時ログはKatalon Studioのウインドウ右下のLogViewに表示されます。ではTest Suiteを実行したときつまり複数のTest Caseをまとめて実行したとき、各Test Caseを実行した時のログをどこで見ることができるのか？

[Reports](https://docs.katalon.com/display/KD/Test+Suite+Report) を使います。Katalon Studioのウインドウ左サイドのTests ExplorerのなかにReportsというアイコンがあります。Reportsをクリックすると、Test Suite `TS1`を実行したときのログがタイムスタンプ別に保存されているのがわかります。ひとつのタイムスタンプを選択してダブルクリックしましょう。

するとTest Suiteを構成するTest Casesが列挙されてそのログにアクセスできることがわかります。さらに
![ShowTestCaseDetails.PNG](https://qiita-image-store.s3.amazonaws.com/0/52995/8b5acdd5-ea15-d6b8-1138-61f3b2ac6426.png)というボタンをクリックすれば、各Test Caseのログの詳細が表示されます。

つまりReportsを使えば下記のようなGUIでTest Suitesの実行結果をみることができます。
![Reports.png](https://qiita-image-store.s3.amazonaws.com/0/52995/3aeb33f1-8fb0-bbbd-da8b-9a35d68bd292.png)

## テストの最終成果物 Test Suite Summary

Test Suite毎のSummaryをみればTest SuiteがいつStartしていつEndしたか、Test Caseをいくつ実行したか、FailedしたTest Caseがいくつあったか、Errorがいくつあったかがわかります。

![TestSuiteSummary.PNG](https://qiita-image-store.s3.amazonaws.com/0/52995/83d4d4e6-0c42-8562-3049-2e8342c9e32d.png)

Summaryに表示された判定内容こそが自動化テストの成果物です。もしも Failed>0 あるいは Error>0 だったら悪い兆候です。あなたのWebサイトに問題があるか又は自動化テストのどこかに問題があるにちがいありません。すぐに対処しましょう。

# 結び

Katalon Studioはテスト対象のWebページのスクリーンショットをとる機能を提供しています。次回はスクリーンショットの撮り方を紹介するつもりです。