Pepperボックスライブラリのテスト考

Pepperのアプリケーション開発は、基本的にはChoregrapheというビジュアルプログラミング環境上で、「ボックス」をつなげていくスタイルのインタフェースでおこなうことができ、割と気楽にアプリケーションを開発できます。
開発者は「ボックスライブラリ」から必要なボックスを選び出して、これらをつなげることで、アプリケーションの振る舞い(「ビヘイビア」)を定義することができるという格好です。

標準でついているボックスライブラリでもそこそこのビヘイビアは実現できるのですが、これらのボックスライブラリは必ずしも網羅的にボックスを用意しているというわけではなく、ボックスの実装(Pythonスクリプトなど)をカスタマイズなどしなければならない場合も結構あるのが現実です。こういった部分は、コミュニティベースでボックスライブラリが開発されていくのが現実的なのかなあ、と思ったりするわけです。

じゃあボックスライブラリを作ろう、と思うわけですが、当然、ボックス内にバグを作りこんでしまって後のフェーズで困るのは嫌です。しかしどうも公式にはボックスのテストフレームワークらしきものが見当たらない・・・
そんな感じで、Pepperのボックスライブラリをどうテストしてクオリティを上げていくか、みたいなことについてつらつらと考えながら試作とかしてみているのでそのメモ。

#ざっと考えてみる

###ボックステスト用ビヘイビア？

他のプログラミング言語、たとえばPythonにおけるテストを眺めていると、ボックスが持つ入力・出力・パラメータといった形式は、そのままPythonの「クラス」に置き換えて考えてしまってよさそうです。

たとえばPythonではテスト対象のクラス(のインスタンス)が意図したとおりに振る舞うかどうかをテストケースとして記述します。このテストケースでは、実際にテスト対象のインスタンスに値を入力し、出力された値が期待する値と同一かどうかをチェックするコードを逐一記述します。
Choregrapheでも同じようにテスト用のビヘイビアを用意して、この中でテスト対象のボックスと結果チェック用のボックスをつなげていくのが自然な感じがします。たとえば、Waitボックスのテストならば、Waitボックスが入力を受けてn秒後に必ず出力をすること、n秒より前には出力をしないこと、とか。


###ボックスライブラリとボックスの関係？

当たり前なんですが、テストはボックスライブラリ内のボックスとまったく同一のものに対しておこなわなければなりません。ボックスライブラリのものとは違うバージョンのボックスに対してテストしても、ボックスライブラリのボックスが正当かどうか確認したことにはならないわけです。

[Pepperのファイル探訪(プロジェクトファイル)](http://qiita.com/yacchin1205/items/c8fa082120f2d3c0e2b7)でも少し書いたのですが、ボックスライブラリからビヘイビアにドラッグ＆ドロップしたボックスは、ビヘイビア中にはコピーされる形で配置されるようです。これでは、テスト用ビヘイビアを作成しても、そこでのテスト対象のボックスがボックスライブラリ中のものと違っている、みたいな事態が発生してしまい、テストとしての役割を十分に果たせないおそれが出てきます。

このような、ボックスの実装の同一性を維持するためには、ビヘイビア中のボックスとドラッグ＆ドロップ元のボックスライブラリの関連を何らかの形で識別できなければならなさそうな感じがするわけですが、ビヘイビアの定義ファイルの形式を見る限りは、ボックスを一意に識別できるような情報は見当たらない・・・
たとえば、最新ドキュメント、Choregraphe 2.0.5における更新情報のImproved boxesのところには、

> Here is the list of boxes you should cut/replace:

とか(手で置き換えろ的なニュアンス？)、

> Now these boxes call an ALMotion method, so they will be updated automatically by new releases.

みたいな(APIの実装の変更だから自動的に(ボックスの置き換えなしに)更新されるよ的な)記述もあるので、ボックスライブラリ中のボックスに変更があった場合に、ビヘイビア側を自動的に追従させる機構は少なくとも公式にはないような感じがします。

#考えてみる課題

そんなわけで、以下の2つについて考えてみることにします。

1. ビヘイビア内ボックスをボックスライブラリ内のボックスで置き換える(共通化する)方法
2. テスト用ビヘイビアの作り方

ということで、まずは1.、ボックス(のコピー)の同一性をなんとか維持できるようにしてみましょうということを考えてみます。

#試行:ビヘイビア内ボックスをボックスライブラリ内のもので置き換える

自動リプレースツールを試作しました。コードは以下に。

https://github.com/yacchin1205/choregraphe-box-util

Linuxでしか動作テストしてませんが、適当にcloneして `pip install -r requirements.txt; python setup.py install` とかやるとインストールされるはずです。たぶん。
コードはPythonで記述しています。Pythonで独立したツールを書くのは初めてなので色々勉強になりました・・・

なお、XMLの処理にはlxmlを使っています。これはボックスのXMLファイルがCDATAセクションを利用しており、Python標準のElementTreeはCDATAセクションをうまく出力してくれなかったため・・・

使い方としては、

```
$ replace-boxes -l (ボックスライブラリのパス(ディレクトリのみ対応)) (プロジェクトの.pmlファイルへのパス)
```

とかすると、指定されたプロジェクト内のビヘイビアに関して、

1. 指定されたボックスライブラリから、ビヘイビア中にあるボックスと合致するものを探す
2. ビヘイビア中のボックスをボックスライブラリ中のものに(あれば)置き換える

こうして、ビヘイビア中のボックスとボックスライブラリのボックスの同一性を維持しようという発想です。
まだ自分がテスト的に使っているツールなので、試す際は必ずプロジェクトのバックアップをとってから実施するようにしてください。変換の様子だけ確認したい場合は `--dry-run -v` オプションをつけていただけると見えます。

以下、やっていることの詳細を・・・

###ボックスのマッチング

まず、ボックスライブラリとビヘイビア側、それぞれのボックスの対応関係のマッチングが必要になります。
今回は以下の要素が合致しているかどうかを見ています。

* ボックスの名前
* 入出力の個数、それぞれの名前、ID、タイプ
* パラメータの個数、それぞれの名前、ID、タイプ

処理が面倒なのがボックス名です。ボックス名は「Say」, 「Basic Awareness」など、名前空間のようなものを持ちませんので、複数のボックスライブラリで同一名称のものが重複する可能性があります。
また、同一のフローに複数のボックスを配置した場合、「Say (1)」「Say (2)」などコピーを示す番号が振られてしまうので、なおややこしくなります。

####ボックスの識別用タグ

ボックスの名前のマッチングについては「ボックス名 (n)」などという形式を想定したマッチングをおこなっていますが、これだけだと、異なるボックスライブラリで提供されるボックス名の競合をうまく解けません。

そこで、ボックスの説明のところに以下のようなアノテーション的なものをつけることで、これもあわせて合致するか見るようにしています。

```
@source https://github.com/yacchin1205/choregraphe-box-util
```

この `@source` の値を見て、同一のボックスライブラリを由来に持つものかどうかの判定を試みています。この判定を外したい場合は `--ignore-tags` オプションをつければよいようにしています。

####置き換え処理

置き換え時には、基本的にはマッチしたボックスライブラリのボックスをビヘイビア内にコピーします。これにより、ボックスのスクリプトや説明文などが置き換えられます。
例外はParameterのvalueで、これは置き換え元のボックスのものを引き継ぐようにしています。

なお、Text Editのような、Choregraphe上でテキストボックスを表示するようなpluginタイプのボックスは、変換対象としていません(このpluginはボックス内のscript自体を書き換えたりしているようで、よい置き換え方式が思いつかない・・・)
また、ボックスにリソース(音声ファイルなど)が結びついている場合の置き換えは未対応です。

そんなわけで限定的ではありますが、ビヘイビアとボックスライブラリ間でボックスの同一性を維持できそうになったので、テスト用ビヘイビアを作ってみます。

#試行:テスト用ビヘイビア

いきなり網羅的に作るのはつらいので、[Pepperくんで HTML5 TEST やってみた](http://qiita.com/yacchin1205/items/a81ea84e09843c1d3e1e)で作り始めたボックスライブラリのうち、Show URLボックスをお題にして簡単なテスト用ビヘイビアを作ることにしました。

https://github.com/yacchin1205/pepper-web-boxes

テスト用ビヘイビアは `tests/test-show-url` にあります。

####成功することのテスト

Show URLが成功することのテストはこんな感じ。

![test-show-url-success.png](https://qiita-image-store.s3.amazonaws.com/0/28770/0ae10d80-ce84-b596-6040-fda59555a8c4.png)

大まかには以下の2つのフローからなります。

1. Enable WiFiボックスとGet WiFi statusボックス(いずれも独自ボックス)でタブレットがCONNECTED状態になったことを確認
2. Show URLボックスを実行し、ある一定時間のうちにonSuccess出力が発火するかどうかをみる

ポイントは2.で、Show URL下のWaitボックスにより、開始から10秒間のうちにonSuccess出力が発火されなければ(Assert BangのonInput入力に何も入力されていなければ)エラーである旨がログに出力されるようになっています。
また、onFailure出力からFailureボックスに入力されたら、即時エラー扱いとしてログに出力することもおこなっています。

このビヘイビアを実行するだけで、Show URLボックスが意図した動作をしているかどうかをエラーメッセージの有無で確認することができます。

####失敗することのテスト

逆に、Disable WiFiの後にShow URLを実行するとエラーになることもテストを記述しています。

![test-show-url-failure.png](https://qiita-image-store.s3.amazonaws.com/0/28770/0c90487c-4e83-afa5-bbff-8d31f343e339.png)

ここでは、Disable WiFiを実行した後にShow URLを実行し、onFailure出力が実行されることをAssert Bangボックスにより確認しています。意図と反してonSuccessが出力された場合には、Failureボックスによりエラーであることを明示しています。
これにより、ボックスが動作しない状況における処理も意図通りになっているかを確認できるわけです。

これらのテストにおけるShow URLボックスは、ビヘイビア中はそれぞれ別のボックスとして記述されていますが、先の `replace-boxes`コマンドにより、ボックスライブラリとの同一性を維持することができます。Show URLボックスにミスがあったりしても、テストビヘイビア中のボックスを書き換えて再度テストをすることが可能です。


#まとめ

そんな感じで、ボックスの同一性を維持するためのツールと、ボックスが想定したとおりに動作するかのテスト用ビヘイビアを書いてみました。

個人的にはChoregrapheの割り切りは非常に好みなので、このような補助的なツールをちょこちょこと開発していけるとみたいに思ったりしています。

そのうち、ボックスライブラリのドキュメント生成ツールみたいのもほしいですねー・・・Choregraphe添付のボックスライブラリはドキュメントが見当たらなかったりしますし、ないんじゃないのかなあと想像。