読者です 読者をやめる 読者になる 読者になる

ささいなことですが。

Windowsアプリテスト自動化ライブラリFriendly開発者の日記です。

Friendlyの処理実行~プロセス、スレッド、同期、非同期~ その1

Friendly(Win32, WinForms, WPF)

これは「Friendly Advent Calendar 2014 - Qiita」の記事です。
昨日は、Frienldyの誕生まで話ましたー。

Friendlyはこんな感じで簡単に、別プロセスのAPIを実行させることができます。
f:id:ishikawa-tatsuya:20141203001922p:plain

使えるのは
.Netならフィールド、プロパティー、メソッド
public、protected、internal、private、
staticでもインスタンスでも・・・
とにかく全部です!

ネイティブはDLL公開関数だけですけど、
それだけで簡単にAPを公開できるで、非常に簡単です。
それに、kernel32.dllとかuser32.dllとかは既に組み込まれていますからそれは使えますよね。

詳細はこちら参照お願いします。
テスト自動化 Friendly - 株式会社Codeer (コーディア)
このブログでも、そのうちハンズオン形式で伝えるシリーズ書きます。

処理実行スレッド

なのですが、「それを実行しているスレッドは誰なんだ?」って話です。

//テストプロセスでは、実行命令を出しているだけ
//じゃあ、実際に実行するのは?
string ret = form.Func(3);

まあ、ユーザーのみなさんは直感でメインスレッドだろうなーって思ってますよね?
はい、当たりです。普通に書くとそうなります。
Friendlyユーザーの中でもあんまり知られていないのですが、実は指定することができます。
それは、WindowsAppFriendのコンストラクタです。
普通に使うと、多分Processを渡しますね。

//こんな感じ
var app = new WindowsAppFriend(Process.Start("Target.exe"));

こうすると、そのプロセスのMainWindowが属するスレッドで処理が実行されることになります。
あと、実はウィンドウハンドルを渡すバージョンもあって、それは渡したウィンドウの属するスレッドで処理が実行されるようになります。
途中で実行スレッド変更するインターフェイスもWindowsAppFriendにあるんですよー。
WindowsAppFriend - 株式会社Codeer (コーディア)
まあ、僕もFriendly自体のテストでしか使ったことないんですけどねw。

まあ、普通は相手プロセスのメインスレッドで動作すると考えてください。
だから、GUIコントロール操作しても例外発生しないし、変に排他制御しなくてもいいのです。

基本は同期実行

それでですね。
それを踏まえて、もう一回このコードを見てください。
戻り値を取得してますよね?
呼び出しスレッドと実行スレッドは異なるのです。
取れないことってないのでしょうか?
答えは「絶対取れるです。」
(もちろん途中で相手プロセスが不正終了したり、呼び出したメソッド内部で例外が発生したら話は別ですが。)

なぜかというと、Friendlyの呼び出しは同期制御しているからです。
わざわざ、やってます。
これは、前にも書きましたが、テスト実行に非常に重要なことなのです。。
だって、指示した処理が確実に終了してから、次の指示を出すなり、状態取得するなりしないと、安定したテストは書けませんよね?
こんな感じです。
f:id:ishikawa-tatsuya:20141204013721p:plain

じゃあ、重い処理の場合は?

待ちますとも。いつまでも。
だって、テストですよ?
その処理が終わらなかったら判定できませんよね?
指示を出すテストスクリプトだけ先に終了しても、なんも嬉しくないですよ。
f:id:ishikawa-tatsuya:20141204013720p:plain

待ってる時間に別のテストしたら?

まあ、その発想は当然ですよね。
いくらFriendlyが高速にテストできるといってもシステムテストは時間がかかるのです。
1000ケースも回せば、1時間くらいすぐ行きますよ。
重いテストがあるなら、その間に別のやりたいですよね。
でも、並列化するなら、お勧めは全く別のマシンでです。
一つのPCで複数のアプリ起動して並列でテストするのは難易度高いです。
操作対象がフォアグラウンドでなくても問題なく処理が実行できるテストケースのみ集めると可能ですが特殊ケースです。
さらにあえて、重い処理の隙間のみ狙うとか神業すぎます。
f:id:ishikawa-tatsuya:20141204013726p:plain

相手プロセスが不正にフリーズした場合は?

これは、聞かれます。
で、どうすればいいかというと、相手プロセスに時間が来たら終了する爆弾を仕込むのです。
(Friendlyなら簡単に仕込めますよね。)
呼び出し中に相手プロセスが終了すると、例外を飛ばしてくれます。
で、テスト実行時間は今時のテストフレームワークならわかるので、それが分かります。
こんな感じです。
f:id:ishikawa-tatsuya:20141204121714p:plain
f:id:ishikawa-tatsuya:20141204121716p:plain
これも、ポイントはチマチマやらないことですね。
・N分を超えるシナリオを基本書かない。
・どうしても、超えるときは特別に設定する。
っていうルールをプロジェクトごとに決めておくとよいと思います。
普通のテストの実装には出てこないようにするとよいと思います。
テストはシンプルであるべきなのです。

同期処理最高!でも・・・

つまり、呼び出しが同期であることは絶対的な正義なのです!

・・・
しかしですね。
ただ一つだけ、私9は年Windowsアプリ自動化やってますけど、たった一つだけです。
同期では困るケースあるのです。
しかも、一つだけなんですけど、頻出問題なのです。

その結果、Friendlyではライブラリとして、同期を取らない方法、つまり非同期をサポートしました。

明日に続く・・・