UWSC を使った自動テスト

この記事は [Sansanアドベントカレンダー](http://qiita.com/advent-calendar/2015/sansan) 21日目です。

# 概要
* UWSC で自社製 Windows アプリケーションのテストをする
* この記事では、Windows の メモ帳 の置換機能の自動テストを試してみます

# UWSC とは
ざっくりいうと、キー操作などをスクリプトで記述・再生することができます。
詳しくは、↓を参照下さい。
http://www.uwsc.info/

UI 操作の再現ができるので、効率的に UI 操作を伴うテストができます。
（※Window の作りによっては、容易に操作できないアプリケーションもあります）

# メモ帳の置換機能をテストしてみる
`ABC` を入力して、「`A`を`1`に置換」すると、`1BC`になっていることを確認する。
## Windows のメモ帳
　<img width="417" alt="メモ帳.png" src="https://qiita-image-store.s3.amazonaws.com/0/9695/4d0770e6-282e-7aa1-89cd-b05d0074b0ba.png">
置換ダイアログの UI パーツなど、↑でイメージしておいて下さい。
## 手順（`A` を`1` に置換する）
* メモ帳を起動する
* メモ帳に `ABC` と入力する
* 置換ダイアログを開く
* `検索する文字列(N)` に、`A` を入力
* `置換後の文字列(P)` に、`1` を入力
* `全て置換(A)` ボタンを押下
* メモ帳の文字列が、`1BC` になっていること

## UWSC のコード（サンプル）
※ 置換結果の検証だけを目的としているため、メモ帳の終了とかまでは面倒見ていません

```uwsc:notepad_test.uws
メモ帳テスト.起動()
メモ帳テスト.文字入力("ABC")
メモ帳テスト.置換("A", "1")

// 比較
IFB メモ帳テスト.比較("1BC") THEN
    MSGBOX("一致")
ELSE
    MSGBOX("不一致")
ENDIF


CLASS メモ帳テスト

    DIM メモ帳App // メモ帳の Window ID を保持しておく

    PROCEDURE 起動()
        EXEC("notepad.exe")
        メモ帳App =GETID("メモ帳") // ウィンドウタイトルが "メモ帳" のウィンドウID
    FEND

    PROCEDURE 文字入力(文字)
        SENDSTR(メモ帳App, "ABC")
    FEND

    PROCEDURE 置換(検索文字列, 置換文字列)
        置換DLG = 置換ダイアログの表示()
        SCKEY(置換DLG, VK_ALT, VK_N) // 検索する文字列(N)にフォーカスを当てる
        SENDSTR(置換DLG, 検索文字列) // 検索する文字列を入力
        SCKEY(置換DLG, VK_ALT, VK_P) // 置換後の文字列(P)にフォーカスを当てる
        SENDSTR(置換DLG, 置換文字列) // 置換文字列を入力
        SLEEP(1) // デモの便宜上入れた
        CLKITEM(置換DLG, "すべて置換") // [すべて置換]ボタンをクリック
        KBD(VK_ESC) // ダイアログを閉じる
    FEND

    FUNCTION 置換ダイアログの表示()
        // 置換DLGを表示　Alt, E, R
        SCKEY(メモ帳App, VK_ALT, VK_E, VK_R)
        SLEEP(1) // 表示されるまで待つ
        RESULT = GETID(GET_ACTIVE_WIN)
    FEND

    FUNCTION 比較(期待値)
        // クリップボードにテキストを積む（全選択後コピー）
        SCKEY(メモ帳App, VK_CTRL, VK_A)
        SCKEY(メモ帳App, VK_CTRL, VK_C)
        // 比較
        クリップボード文字列 = GETSTR(0)
        RESULT = (クリップボード文字列 = 期待値)
    FEND

ENDCLASS
```

## テストコードを実行する
いろんなやり方があります。

* UWSC を起動しておいて、読みこみ → ファイル選択 → 再生
* UWSC を起動しておいて、`notepad_test.uws` ファイルをドラッグ＆ドロップ
* コマンドラインで、`>UWSC notepad_test.uws` を実行（パス設定はよしなに…）

自動テストを想定するので、実運用は人手をかけないコマンドラインになるでしょう。

## 実行結果
<img width="251" alt="成功.png" src="https://qiita-image-store.s3.amazonaws.com/0/9695/27ff7d0b-8267-70a2-970d-376bf0d52e34.png">
ちゃんと成功しましたね。

## 試しに、失敗させてみる

上記テストコードを
```
IFB メモ帳テスト.比較("ABC") THEN
```
ってして実行すると・・・

<img width="282" alt="失敗.png" src="https://qiita-image-store.s3.amazonaws.com/0/9695/25eddfb5-81e0-418f-eee5-ef700f57dda7.png">

ちゃんと失敗しますね。

## 弊社での導入例
弊社では、Windows 上で動くアプリケーション（← Web アプリケーションではない）もあるので、そのアプリケーションで UWSC を導入した自動テストを実施しています。
今まで人力でテストをしていた部分を、自動で確認できるようになったので、テスト工数の大幅削減＆容易な品質維持が可能になりました！

## 実運用するなら…
* テスト結果を JUnit 形式で出力する
 * UWSC では `FPUT` 関数で CSV 形式で出力しておいて、後で別プログラムで XML 形式にコンバートするなど
* アプリケーションの起動や、ダイアログが表示されるのを `SLEEP` 関数じゃなくて、状態チェックを行うようにする
 * `SLEEP` はマシンによっては多すぎるかも知れないし、少なすぎるかも知れない。
 * `GETID` を一定時間 while で回して、チェック。タイムアウトしたらエラーに。

などの対応が必要になります。（この記事では割愛）

# 他に UWSC でできること

* 画像判定（指定した画像が画面内のどこにあるかがわかる）
 * そもそも意図した表示結果になっているかの確認に使える
 * ツールバー上のアイコンや、クリックしたくても指定しづらい場所をクリックするのにも使える
* スクリーンショット保存
 * テストが失敗したときに、スクリーンショットを保存しておくと、原因特定がしやすい 
* COM オブジェクトの操作
 * ブラウザとか、Excel とかも操作できます。 
* DLL の利用
 * `kernel32.dll`, `user32.dll` などの関数も呼び出すことができる
 * → テスト中のアプリケーションのメモリ使用量なんかも取れるかも？

（やったことありますが、この記事では割愛）

# 言いたいこと
ユニットテストだけではカバーしきれない UI 操作も伴うテストも自動化して、テスト工数を削減して開発効率を向上させよう！

# スマホでは！？
同様に自動テストできます！（弊社ではやってます）
↓あたり参考にして頂ければ幸いです。

* [Appium を使って iOS / Android の UI テストを共通化](http://www.slideshare.net/kenichitatsuhama/appium-ios-android-ui)
* [Robotium を使った UI テストとレイアウト確認の効率化](http://www.slideshare.net/kenichitatsuhama/robotium-ui)

それではみなさま、良いお年を。。。