Web開発のように、WinFormsをシステムテストしたい
VB.NETなどでWindows Formsの開発をしていると、Web系のSeleniumなどのテストツールがうらやましく思えます。Visual Studioにも「コード化されたUIテスト」なるものが存在しますが、Visual Studio Premium以上でなくては使えません。ちっちゃなプロジェクトばかりの会社では、1人月に匹敵するようなツールは、なかなか手がでないのが実状です。それに、操作を記録する形式なので、BDD(Cucumberみたいな)のようなやり方には不向きです。
Ruby + LDTPでテスト
Spec Flowや、PowerShell、IronRubyなど、なんやかんや試して、最後に行きついたテスト方法が「Ruby + Cobra WinLDTP」の組み合わせです。(某所で紹介した方法です)
Cobra WinLDTPをダウンロードしよう
WinLDTPは、VMWareがオープンソース化し、今は、freedesctop.orgがメンテナンスをしているソフトウェアです。
下記のホームページからダウンロードできます。ダウンロードボタンを押してダウンロードして下さい。
Cobra WinDLTPをインストールする。
CobraWinLDTP-4.0.0.exeをダブルクリックすると次の画面が立ち上がります。「accept」にチェックを入れ「Install」ばタンを押してインストールして下さい。
インストールが終了すると、次の画面がでます。
インストール先は、次のパスです。
C:\Program Files (x86)\VMware\CobraWinLDTP
Rubyのクライアントは次のパスです。Cobra WinLDTPはMITライセンスですが、このクライアントのソースはLGPLなので、ソースの改変などには注意してください。メールで問い合わせたところ、COORDINATORのnagappanal氏は、「機会があればMITライセンスにしたい」とおっしゃってくれていますので、いずれクラアントもMITライセンスになると思います。
C:\Program Files (x86)\VMware\CobraWinLDTP\ldtp\ldtp.rb
パスが通っていることを確認して下さい。
RUBYLIB=C:\Program Files (x86)\VMware\CobraWinLDTP\ldtp\
次に、コマンドプロンプトを『管理者』として立ち上げて、次のコマンドを実行します。これは、LDTPがXML-PRCを使用しているため、HTTPの名前空間の予約が必要なためです。ユーザー名がyamadaなら、次のようになります。
> netsh http add urlacl url=http://localhost:4118/ user=yamada
> netsh http add urlacl url=http://+:4118/ user=yamada
> netsh http add urlacl url=http://*:4118/ user=yamada
irbで次のように打って、何やらオブジェクトが生成されれば、設定は完了です。
irb(main):002:0> require 'ldtp'
=> true
irb(main):003:0> ldtp = Ldtp.new('*')
=> #<Ldtp:0x00000002e51120 @poll_events={}, @window_name="*", @client=#<XMLRPC::Client:0x00000002e50e28 @http_header_extra=nil, @http_last_response=#<Net::HTTPOK 200 OK readbody=true>, @cookie=nil, @host="localhost", @path="/RPC2", @proxy_host=nil, @proxy_port=nil, @use_ssl=false, @timeout=30, @port=4118, @password=nil, @user=nil, @auth=nil, @http=#<Net::HTTP localhost:4118 open=true>, @parser=#<XMLRPC::XMLParser::REXMLStreamParser:0x00000002e41ef0 @parser_class=XMLRPC::XMLParser::REXMLStreamParser::StreamListener>, @create=#<XMLRPC::Create:0x00000002e50c98 @writer=#<XMLRPC::XMLWriter::Simple:0x00000002e50cc0>>>>
RubyからLDTPを使ってみよう
まずは、RubyからLDTPを使って電卓を操作してみましょう。まずは電卓を立ち上げて、次のコマンドを打ってみて下さい。(irbでは、文字コード変換の必要あり)
irb(main):004:0> p_sjis = Proc.new {|s| print s.encode('Windows-31J')+"\n"}
irb(main):005:0> ldtp.getwindowlist().map(&p_sjis)
pane0
frmirb
frm電卓
=> [nil, nil, nil]
LDTPはWindowに対して'frm'のプレフィックス(マップ)が付きます。電卓のウィンドウにアクセスするためのLDTPのオブジェクトを作りましょう。"guiexist"メソッドで、"1"が返ることを確認してください。ウィンドウが存在しないと"0"が返るか、もしくは、例外が発生します。ウィンドウ名に日本語が含まれているときは、文字コードを"UTF-8"にするのを忘れないでください。
irb(main):026:0> calc = Ldtp.new('frm電卓'.encode('UTF-8'))
irb(main):027:0> calc.guiexist()
=> 1
次に、コントロール(オブジェクト)の一覧を取得します。
irb(main):029:0> calc .getobjectlist().map(&p_sjis)
pane0
ukn0
lbl実行履歴
lblメモリ
lbl結果
lbl0
btnメモリのクリア
btnバックスペース
btn7
btn4
btn1
btn0
btnメモリ呼び出し
btn入力のクリア
btn8
btn5
btn2
btnメモリ保存
btnクリア
btn9
btn6
btn3
(中略)
btn除算
btn乗算
btn減算
btn加算
(中略)
mnuヘルプ(H)
=> [nil, nil, nil, (中略)]
それぞれのプレフィックスは、"pane"がパネル、"lbl"がラベル、"btn"がボタン、"mnu"がメニュー、"ukn"がLDTPでは識別不能なコントロール(※1)となります。6番目に"lbl0"とありますが、これが、どうも、電卓で"0"と表示されている結果のラベルです。
(※1)現在のところ、"DataGridView"が"ukn"になります。今後のサポートに期待です。
では、次に"10+5"の結果、ラベルが"15"に変わるのを確認しましょう。
irb(main):036:0> calc.click('btn1');calc.click('btn0')
=> 1
irb(main):039:0> calc.click('btn加算'.encode('UTF-8'))
=> 1
irb(main):040:0> calc.click('btn5');calc.click('btn等号'.encode('UTF-8'))
=> 1
ラベルだけ取得すると"lbl0"の代わりに"lbl15"が取得できることが分かります。
irb(main):041:0> calc.getobjectlist().map{|s| print s,"\n" if /lbl/ =~ s}
lbl実行履歴
lblメモリ
lbl結果
lbl15
まとめ
長くなりましたが、今回はここまで。WindowsのウィンドウをRubyからLDTPを使って操作できることまでを紹介しました。
Rubyから操作、値の取得ができれば、あとは、RSpecでも、minitestでも、CucumberでもTurnipでも、なんでも使ってテストできます。Rubyで、Windows開発のシステムテストの自動化が行えるという素敵環境の出来上がりです!
会社でRubyが使いたいけど使えないプログラマーの方がいらっしゃっいましたら、是非とも社内でRubyを認めさせる突破口に利用してくださいw
Rubyの利用シーンを増やしてRubyの普及促進を!
(余談)
私は、Gherkin書式のExcelファイルをRubyで読み込ませてテストするスクリプトを自前でサクサクっと作って使用しています。「会社の人がテキストファイルは嫌だ!Excelにして!」とわがままを言われたからです。Cucumberが使いたかったのに、「Excelが嫌いなSEはいない!」と痛感しました…。