friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

31
Friendly 始める Windows アプリ システム テスト自動化 内部使用技術解説

Upload: tatsuya-ishikawa

Post on 05-Jul-2015

981 views

Category:

Software


2 download

DESCRIPTION

2014/08/23 わんくま横浜勉強会の資料

TRANSCRIPT

Page 1: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

Friendlyで始めるWindowsアプリシステムテスト自動化

+内部使用技術解説

Page 2: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

石川達也

株式会社Codeer代表取締役

Microsoft MVP for C#

Windowsアプリテスト自動化歴9年

自己紹介

Page 3: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

システムテスト自動化って?

文字通り人間の代わりにアプリケーションをプログラムが動かして成否判定をすることです。

Page 4: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

お得?コストを抑えたらね(・∀・)

エラー!

成功

開発期間中、実行し続ける。デグレを早期に検出。

テストの作りが悪くて不安定

仕様変更等でメンテ

作成

指定のケースではデグレがなかったという情報を取得できた!

BugFix実行

Page 5: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

OS層

Winコア(User32,Kernel32とか)

MS,他ベンダGUI

ユーザ実装

←SendInput 不安定、遅い

←Win32Api

←UIAutomation

難しい操作できないのもある

GUIアプリをプログラムからどうやって操作するの?

Page 6: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

ところで、同一プロセスからだったら操作できるでしょ?

//当たり前void Operation(){

_comboBox.SelectedIndex = 1;}

Page 7: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

そこで、Friendlyですよ!

Page 8: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

Friendly

他のとは根本的に違います。対象プロセスと、友達になって、まるで、同一プロセスでプログラムするように我が物顔で操作できるのです!

最強

Page 9: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

①君のものは僕のもの

public partial class MainForm : Form{

ComboBox _comboBox;

string MyFunc(int value){

return value.ToString();}

}

public void YourThingIsMine(){

var process=Process.GetProcessesByName("Target")[0];

//友達になると・・・var app = new WindowsAppFriend(process);

//別プロセスのオブジェクトを//自分のプロセスのもののように操作できる。dynamic form = app.Type<Application>().OpenForms[0];

form._comboBox.SelectedIndex = 1;

string ret = form.MyFunc(3);}

そ、そんな・・・

.NetはもちろんNativeのDLL公開関数もOK!

Page 10: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

②僕のものは君のもの

void MyThingIsYours(){

var process= Process.GetProcessesByName("Target")[0];var app = new WindowsAppFriend(process);

//自分のコードを動的にインジェクション!WindowsAppExpander.LoadAssembly(app, GetType().Assembly);

//挿入したコードを相手プロセスで実行app.Type(GetType()). ForTest();

}

static void ForTest() { /*テスト用*/ }

え!? 勝手に?

Page 11: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

上位ライブラリ紹介

基本内部メソッド操作、DLLインジェクション

Win32 WinFormsWPF

(めとべや)

GUI操作ライブラリPinInterface(VSHTC)

記述性UP

拡張も自由自在!Friendlyの上に構築されているから安定感抜群!

//各コントロールをラップする//シンプルで直感的なインターフェイスのみ定義されているvar _comboBox = new FormsComboBox(form._comboBox);

Page 12: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

デモ

Page 13: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

Codeer で検索

eが一個多い

これらはNugetで無料で入手できます!

Page 14: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

自動化環境

+ +

VSもTest作成だけならExpressでOK

+

FriendlyFriendly.WindowsFriendly.Windows.NativeStandardControlsFriendly.FormsStandardControlsFriendly.WPFStandardControlsFriendly.PinInterface

VSTest

Page 15: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

ということは?

・ツール購入コスト無料

・簡単なインターフェイス、既知のインターフェイス→作成コスト減

・安定感抜群→運用コスト減

・テスタビリティーを容易に操作→作成、メンテコスト減

・高速な動作→実行時間減

Page 16: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

備考) テスタビリティー操作(自動化と相性悪いコード)

//ここの結合は不安が少ないvoid Event(object sender, EventArgs e){

EventCore(PointToClient(Control. MousePosition));}//これをFriendlyで呼び出すvoid EventCore(Point mousePosClient){//ここから先のロジックをテストしたい。

}

プロダクトを変更。難易度高くて効果の低い部分は自動化しない。効果の高い部分のみ呼び出せるようにする。

・キー、マウス直接参照・D&D・OS提供のGUIetc…

・タイマ・非同期・ペイントイベントを利用したトリッキーコードetc…

Page 17: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

コスパに優れた自動テスト構築が可能!

明日からでも自動化しよう!

Page 18: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

・・・

知ってますよ。わんくま横浜は、こんなことじゃ満足しないんでしょ?

Page 19: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

本邦初公開!

友達の作り方

Page 20: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

最終的にはリフレクションを使っています。でも、普通は自プロセスにしか使えないですよね?

//いくら探してもみつからないforeach (var assembly in AppDomain.CurrentDomain.GetAssemblies())

{var type = assembly.GetType(“Target.ClassA”);

}

//当たり前だけど、自分のプロセスのFormしか見つからないvar forms =(FormCollection)typeof(Application).GetProperty("OpenForms").

GetGetMethod().Invoke(null, new object[0]);

Page 21: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

ということは、こうですよ。

リフレクション実行!

Dll Injection!

これに話しかける。関数名、引数を渡す。

あれ?テストプロセスと友達だった気がする…

Page 22: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

Win32APIを使ってDLLインジェクション

//インジェクションできるのはネイティブDLLのみ

//対象プロセスにメモリ作成IntPtr path = VirtualAllocEx(...);

//ロードさせたいパスを書き込みWriteProcessMemory(path, ...);

//LoadLibraryのアドレスを取得//★Kernel32は常に同じアドレスにロードされる!IntPtr pFunc = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryW");

//LoadLibraryを対象プロセスで実行!CreateRemoteThread(..., pFunc, path, ...);

入りました!

Page 23: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

ところで、 CreateRemoteThreadに渡す関数ポインタの型

CreateRemoteThread(..., pFunc, ...);

//pFuncの型はコレに合致するものtypedef DWORD (__stdcall *LPTHREAD_START_ROUTINE) (

[in] LPVOID lpThreadParameter);

//あれ?戻り値・・・HMODULE LoadLibraryW(LPCWSTR lpFileName

);

64bitのとき、合ってないやん! ∑( ゚Д゚ノ)ノ

Page 24: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

HMODULE Func(LPCWSTR){

HMODULE m = nullptr;return m;

mov rax,qword ptr [rsp] }

int _tmain(int argc, _TCHAR* argv[]){

LPTHREAD_START_ROUTINE f = (decltype(f))Func;auto ret = f(nullptr);

call qword ptr [f] mov dword ptr [ret],eax

return 0;}

実験してみました!

戻り値使わなかったら全く問題なし (゚∀゚;)

HMODULEを戻り値に使ってもレジスタしかつかわない

情報が落ちただけ

Page 25: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

挿入したDLLのAPIを呼び出し//自分のプロセスで関数ポインタを取得IntPtr mod = LoadLibrary(dllPath);IntPtr proc = GetProcAddress(mod, procName);

//差分を計算var distance = …;//proc - mod; x64とx86で型が違う

//相手プロセスの中でのDLLのアドレスを取得IntPtr targetDllAddress;EnumProcessModules(...)...

//差分を足したら、対象プロセス内での関数ポインタになるIntPtr pFunc = …;//targetDllAddress + distance;

//指定の関数を対象プロセスで実行!CreateRemoteThread(..., pFunc, path, ...);

Init()

初期化開始!通信サーバー立ち上げるよー

Page 26: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

呼び出された関数内で.Netのアセンブリをロード//ホストAPIを使って.Netの機能呼び出しICLRMetaHost *pMetaHost;ICLRRuntimeInfo *pRuntimeInfo;ICLRRuntimeHost *pClrRuntimeHost;

CLRCreateInstance(... , IID_PPV_ARGS(&pMetaHost));

//pRuntimeInfoの検索//ルールはWindowsAppFriendのコンストラクタ参照...

//CLR開始pRuntimeInfo->IsLoadable(...);pRuntimeInfo->GetInterface(... , IID_PPV_ARGS(&pClrRuntimeHost));pClrRuntimeHost->Start();

//.Netのアセンブリのロードと目的のメソッド呼び出しpClrRuntimeHost->ExecuteInDefaultAppDomain

(asm, type, method, args, &ret);

もちろん.Netの機能がいるよねー。

Page 27: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

.Netのアセンブリインジェクションで気を付けること

//アセンブリの解決AppDomain.CurrentDomain.AssemblyResolve += ...;

アセンブリの解決!GAC、プロービングパス以外のDLLは、中途半端にしか使えない。AssemblyResolveで解決

ハマりポイント!

Page 28: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

後は、通信サーバーを立ち上げる

僕たち、友達になりました! サーバーと言っても単なるWindow

WM_COPYDATAを使うとリッチなデータが送受信できる!

SendMessageでデータもらってます。でも、COM対策はしてるので例のルールは気にしなくてOK!

Page 29: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

求む! Friendlyエバンジェリスト

今日実演したデモができるセットをご用意いたしております。Friendlyのデモは手品のようなので、LTや宴会でやったら、うけること間違いなし!

また、会社に導入したいとき、上司に見せると効果アリ!?

こちらからダウンロードできます。http://www.codeer.co.jp/download

Page 30: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

お知らせ 登壇予定

9/20 Boost.勉強会 #16 大阪http://osakaboostjp.doorkeeper.jp/events/14150

9/11 SQIPシンポジウムhttp://www.juse.jp/sqip/symposium/timetable/day1/

Page 31: Friendlyで始めるwindowsアプリシステムテスト自動化+内部使用技術解説

ご清聴ありがとうございました。明日からでもFriendlyで自動化を始めましょう!

http://www.codeer.co.jp/AutoTest

picture Dawn Huczek