2012年8月26日日曜日

JsTestDriverでDOM操作を行うための妄想(その2)

妄想に取り付かれると、無敵のキラ様に殺されたりする。

さっきの続き。

JsTestDriverでDOM操作のテストを実行するには
・DOM API(docment.~とかJQueryのものとか)をつかう。
・ 【/*:DOC foo = <div><p>foo</p></div>*/】って擬似DOMにアクセスする
の2パターン存在する。
その他のjs単体テストモジュールと違い、静的なhtmlファイルを参照したりすることは
できない(あくまで現時点では)。
オプションでいかにも静的なhtmlを参照できるかのような物が存在するが、
あれは非同期通信の時などに参照するためのものであって、決して
DOMテスト用ではない。引っかからないように。

まだきちんと試せたわけではないが、後者はthisの扱いがちょっとおかしい。
理由として、jsでthisといえば、
・イベントが発生している時はその発生もとのコンポーネント
・そうでないときは自分自身(クラスとか)
だったりするが、JsTestDriver的にはthisは【:DOC foo】で指定した要素を指してしまう
ので、挙動がおかしかったりする。

そんな感じで怖いから、前者を使いたい。

とはいうものの、今度はそのDOM APIがめんどくさくなってくる。
解決方法としては、seleniumと連携して、htmlを取得し、そのhtmlを解析してDOM APIに置換。
testjs自体に結果をインサートして使用するとかになるのかな。

そんなめんどくさいことしなきゃ

JsTestDriverでDOM操作を行うための妄想(その1)

仕事(がうまくいくためにどうすればいいかを妄想するの)が好き。

Seleniumを使って自動テストをするのはいいけれど、世の中うまい話には裏がある。
ネックとしては
・実行時間
・環境の構築
この2点。

どうしても実際の通信、およびブラウザ動作を行うSeleniumは実行するのに
時間がかかるし、DBやHTTPサーバーといった環境も含めて
運用を考えないといけないから手間もかかる。

この2点をクリアできるのが単体テストであり、有名どころとしては
javaでいうとJUnit。javascriptでいうとJsTestDriverだったりする。

理想的な住み分けとしては
・カバレッジやデグレ防止のためのテストケースを増やしたりしたりするには
 出来る限り単体テストで。
・単体テストで無理な部分(業務的な処理フロー等)は画面テストで行い、
 実行時間を短くする
のがいいのかなと現時点では思っている。

で、そこで今度問題になってくるのが単体テストにおける擬似操作データ、
および擬似通信になってくる。
画面テストにおいては、実際にブラウザも立ち上げ、データベースや
アプリケーションサーバーも存在するから、環境さえ用意してしまえば、
「どのように動かすか」を設定してあげればいいだけ。
だけど単体テストはそうも行かない。あくまで「単体」だから、いわゆるMock的な物が
必要になってくる。

具体的な物の一つに、JsTestDriverでいうところのDOMの操作を行うテストが
当てはまる。

2012年8月25日土曜日

JMeterでDWR通信

ところがどっこい、そういうわけにはいかない。

JMeterでDWR通信を行う際に気をつけなければいけないことがある。
1.httpSessionId
2.scriptSessionId
3.URLパラメータ区切り文字


1.httpSessionId
2.scriptSessionId

JMeter自身が積んでるエンジンでJavascriptが実行できるが、
独自関数は実行できないため、Javascriptを実行して各idを取得することは
出来ない。
なので、これらはレスポンスから正規表現を駆使し、取得する必要がある。

3.が結構なはまりどころ。
JMeterには自身をプロキシサーバーにしたて、http通信を傍受し、テストケースを
作成する機能がある。
いかんせん便利すぎるこの機能の落とし穴。JMeterが取得したhttpリクエストは
各パラメータが半角スペースで区切られており、このままだとサーバーサイドで
パラメータを認識できず、下記のようなエラーが帰ってくる。

********************************************************************

throw 'allowScriptTagRemoting is false.';
//#DWR-REPLY
if (window.dwr) dwr.engine.remote.handleBatchException({ name:'java.lang.IllegalArgumentException', message:'Failed to find parameter: scriptSessionId' });
else if (window.parent.dwr) window.parent.dwr.engine.remote.handleBatchException({ name:'java.lang.IllegalArgumentException', message:'Failed to find parameter: scriptSessionId' });
********************************************************************

これを解決するには半角スペースを全て改行コードに置換してやる必要がある。
お勧めとしてはユーザー定義変数を作成意思、名前に【RN】、
値に【${__javaScript("\r\n",)}】と設定する。

その後、パラメータの空白部分に${RN}と設定すれば、通信パラメータが改行で区切られることになり、無事通信が走るようになる。

JMeterの正規表現

乱数を使って色違いミュウツーを取る簡単なお仕事です。

日ごろから(ポケモン的に)乱数を駆使して、いい思いをしているが、
今回は足元を救われた例。

JMeterという便利ツールがこの世には存在する。(詳細はググっておください)
で、このJMeter、httpレスポンスから正規表現を駆使して値を取得し、
変数に格納することができ、その値を使って以降のhttpリクエストに
使用したりすることができる。

で、その正規表現の設定がなんともいえない。

参照名:変数名称を記述する。
正規表現:レスポンスから値を取得するための正規表現を記述する。
テンプレート:複数取得時の番号を指定する。
一致番号:無視してok
初期値:初期値を記述する。

ってな感じでどこぞのHPに書いてあったので、そのとおりに設定していたが、
いかんせんうまくいかなかった。

原因は一致番号の設定内容。
空白のままだとなんとランダムで正規表現の内容を引っ張ってくるらしい。(詳細不明)

具体的には、DWR3の通信内容からScriptSessionIdなるものを取得しようとして、
出来るときと出来ないときがあった。(2日つぶした、、)

無視していい設定なんてないんだね、よかったね。

(人やDWRと)通信することはむずかしい。

シロのおうとうには答えていきたかったりする。


DWRがブラウザとの通信を行う際、httpパラメータに【http session id】なるものと【script session id】なるものを保持しており、このパラメータをつかって、APサーバーとの通信してる。

なので、純粋にjmeterでhttp通信を捕まえて動作をエミュレートさせようとしても、捕まえた時点でのセッションidをそのまま使用しているため、まともに動作できない。

なので、jmeterのテストケース内で動的にパラメータを取得し、編集する必要がある。

【DWR2の場合】
engine.jsの応答データから正規表現で引っ張ってくればいい。
【DWR3の場合】
ページロードリクエスト(リクエストパスに《__System.pageLoaded.dwr》と設定されている)の
応答データから正規表現で引っ張ってくればいい。

DWR3の方法がどこにも書いていなくて、あせったりした。
でも本当にあせったのはjmeterの正規表現仕様だったりする。

visualVMのアドオン実装

一昔前はライブラつかって
『ねんがんのオニオンソードをてにいれたぞ!』
が実行できた。
今はvisualVMつかってcpu使用率やheap量とか取得できる。

ただしグラフで表示されたりするだけで、正確な数字をログにして記録したりしようと思ったら、
独自にアドオンを開発しなきゃいけない。

開発環境の構築や取っ掛かりはIT Proに任せるとして、詰まったところをメモ書き程度に書いておく。

//まず前提から、こんな感じで書くと、jvmの現在のステータスがわかる
MonitoredDataオブジェクトを取得できる。


        MonitoredDataListener monitoredDataListener = new MonitoredDataListener() {
            @Override
            public void monitoredDataEvent(final MonitoredData data) {
                final long time = System.currentTimeMillis();
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        //ここに書く命令が、一定秒数ごとに実行される
                        hogehoge(data, time)
                    }
                });
            }
        };


//jvmの稼働時間
data.getUpTime()
//cpu経過時間
data.getProcessCpuTime()
//javaマシンの情報を取得したり
Jvm jvm = JvmFactory.getJVMFor(application);
//cpuモニターサポート状況取得方法(boolean)
jvm.isCpuMonitoringSupported();
//javaマシンのプロセッサ数取得(int)
JvmMXBeansFactory.getJvmMXBeans(JmxModelFactory.getJmxModelFor( application ))
              .getOperatingSystemMXBean().getAvailableProcessors();

上記のメソッド組み合わせて、cpu使用率とか取れたりする。メモリはもっと簡単
//最大ヒープサイズ
data.getGenCapacity()[0];
//使用ヒープサイズ
data.getGenUsed()[0];
//最大メモリサイズ
data.getGenMaxCapacity()[0];



そろそろタグ管理したほうがいいかな、、、、

2012年8月4日土曜日

希望を見出しても、重力に魂を引かれたエゴに押しつ(以下略


希望を持つことはいいことです。

seleniumの2.25から複数のCapabilitiesクラスを指定することができるようになった。

今までは
new FirefoxDriver( );
new FirefoxDriver( DesiredCapabilities.firefox() );
new FirefoxDriver( new FirefoxBinary(), new FirefoxProfile(), DesiredCapabilities.firefox());
new FirefoxDriver( DesiredCapabilities.firefox() );
こんな感じでFirefoxを起動していたものが、

  Capabilities cap = DesiredCapabilities.firefox();
  Capabilities cap2 = DesiredCapabilities.firefox();

new FirefoxDriver(  cap   ,  cap2   );
new FirefoxDriver( new FirefoxBinary(), new FirefoxProfile(),  cap ,  cap2 );


こんな感じにできるようになった。
ごっそり変わったソースの変化がデグレを予感させるが、googleさんはデグレなんかしませんよね。

もともとCapabilitiesクラスは起動設定を保持するクラス(プロキシとか、起動オプションとか)
であり、最近はChromeOptionsとかFirefoxProfileが台頭してきて、
ただでさえここ最近は居場所がない状態だった。
関係するコンストラクタもdeprecatedされまくってた。

なぜゆえに、時代に逆行するようなことが起こったのか、起動設定をひとつのブラウザで
複数指定できるようにしてあるのか、いまいち要領が得ない。
多分Firefox14以降の仕様にあわせた感じなんだろうけど。

で、肝心のソースの中身なんだけど、前者のCapabilitiesは希望的な位置づけで
後者のCapabilitiesは必須的な位置づけらしい。

何のこっちゃようわからん。一応Firefoxdriver内では2つのCapabilitiesをマージして
FirefoxProfileに変換し、設定を読み込んでいる。


だったら最初から
  new FirefoxDriver( new FirefoxBinary(), new FirefoxProfile())
これ使えって話じゃないかと思ったりする。今後何か意味が出てくるんだろうか。

なお、CapabilityType.ENABLE_PROFILING_CAPABILITYは希望Capabilitiesに
セットさせて動作させておく模様。