Hatena::Groupmediaforcelabs

御手洗の開発記録

|

2010-05-06

第2回 Seleniumのメリット、デメリットについて

| 17:50

こんにちは。

御手洗です。

今日はSeleniumのメリット・デメリットについてまとめてみたいと思います。

まず、個人的な感想を述べたいと思います。

実は僕、テストが嫌い(苦手)なんです。。。

プログラマとしては、致命的かもしれませんwww

でも、Seleniumはテストしているというより、コーディングしているという感覚になるので、軽快にテストを進めることができました。

個人的には一番これが大きいです。

以上。








あまりにもあっさりしすぎて怒られそうなので、ちゃんとしたまとめに入りたいと思います。

Seleniumのメリット、デメリット

まずは、Seleniumのメリット、デメリットについてまとめてみます。

  • メリット
    • テストの再実行が簡単。
    • プログラムでテストするので人間が見落としやすいNGもきっちりと発見できる。(当然しっかりとしたチェックが記述できているテストケースを作成する必要がある)
    • Seleniumテストケースがしっかりできていれば、テスト実行自体は夜間実施することできるので時間を短縮できる。
    • テストをしてて眠くならない。(個人的な意見ですw)
  • デメリット
    • 画像の内容など目視で確認するしかできないこともある。
    • Seleniumの知識がないとテスト工数が増加してしまう。
    • テスト回数を重ねるごとに味がでるため、「Selenium作成→テスト」と「人間がテスト」の工数があまり変わらない。(場合によってはSeleniumの方が工数がかかってしまう)

ざっと思いつく限りこんなものです。

もっとあったかもしれませんが、忘れてしまいました。

思いだしたら随時書いていきたいと思います。

で、結論ですが、Seleniumは使った方がいいです!!!(断言)

現実に1回だけテストして終了なんてことはないですし、現在ブラウザの種類はたくさん出ています。

同じテストを何回も実施するケースは多いと思います。

そういうときには、Seleniumのような自動化は大変便利です。

Seleniumでなくともテスト自動化ツールはあるので、状況に応じて適切な自動化ツールを選択することでテストの作業を軽減できると思います。

つづけて、Selenium実行方式のまとめを書きたいと思います。

Windowsバッチファイルを利用したSelenium実行のまとめ(バッチ実行)

※ 以後、このSelenium実行方法を「バッチ実行」とします。

Windowsバッチファイルを利用したSelenium実行のまとめを記載します。

この方法はSeleniumのテストスイートをHTMLで作成し、Windowsのバッチファイルで動かす方法です。

その際、DB更新はクライアントコマンドを利用して行います。

PostgreSQLでしたらpsql.exeです。

以下のような流れになります。

f:id:mitarai2009:20100506181112p:image

このやり方のメリットとデメリットを以下に記載します。

  • メリット
    • HTMLなのでテスト内容を確認しやすい。(ブラウザで見るとテストの内容が把握しやすい)
  • デメリット
    • テストデータ用のSQLを作るのが意外と大変。
    • 更新処理などのテスト結果チェックが大変。

やはり、DBチェックやDB更新処理に問題があります。

JUnitTestNGなどを利用したSelenium実行のまとめ(プログラム実行)

※ 以後、このSelenium実行方法を「プログラム実行」とします。

次に、JUnitTestNGなどを利用したSelenium実行のまとめを記載します。

この場合のテストスイートはSelenium IDEを利用して作成することはできますが、基本は自力でコーディングしたほうが効率的でした。

なぜなら、処理の途中でDB更新を実施したり、テストのつながりなどを定義するため、Selenium IDEから作成したコードをそのまま利用することがないためです。

最初のテンプレートとして利用できるかもしれませんが、JUnitTestNGのコードをSelenium IDEから実行できないのでSelenium IDEを使うメリットは少ないと思います。

このやり方のメリットとデメリットを以下に記載します。

  • メリット
    • DB更新処理をテスト中に挟むことができるので複雑なテストケースを作成するのが便利。
    • DB更新後の値のチェックが比較的やりやすい。(相対的な印象です)
  • デメリット
    • テスト内容が把握しにくい。(これについては別途記載します)
    • EclipseなどのIDEの知識がない場合、テストの実行準備が大変。

こちらは、可読性や専門知識が問題となってきます。

バッチ実行とプログラム実行の比較

これに関しては、Seleniumテストケースを作る人のスキルによって変えていけばいいと思います。

Javaの知識はないけど、テスト仕様書は書けるし、SQLは大丈夫という方ならバッチ実行がお勧めです。

テストを工夫すればバッチ実行でも、漏れなくテストすることが可能です。

また、Javaの知識があり、テストフレームワークは得意という方にはプログラム実行がお勧めです。

DB更新やDBチェックがプログラム実行に比べて容易に実装できるためです。

テスト仕様書について

最後に、テスト仕様書についてです。

プログラム実行のデメリットとして、「テスト内容が把握しにくい。」と書きました。

これは、TestLinkなどを使用することで解消できます。

また、HTMLSeleniumテストスイートについてもちゃんとコメントを記述していないと何のテストだかさっぱりわかりません。

そこで、気になるのがテスト仕様書ってどうするの?というところです。

従来通りのテスト仕様書と呼ばれるものをきっちり作成してSeleniumテストスイートを作成することもできます。

しかし、プログラム実行、バッチ実行ともに言えることなんですが、きっちりコメントを書いていけば、それがテスト仕様書の代わりにすることができます。

これに関しては、どちらがいいとははっきり言えません。

プロジェクトとして、TestLinkで作成した仕様書HTML形式のテスト仕様書で問題なのであれば、それでもOKだと思います。

ただし、どちらの場合でも、テスト項目をきっちり漏れなく上げることが重要となります。

この内容はSeleniumでテストを行う場合でも、人間が行う場合でも同じです。

本日は以上です。

今回は文字ばかりで疲れました。

読みづらかったらすみません。

それでは、また。

AkashAkash2012/02/18 11:58The purchases I make are entirely based on these atrciles.

2010-04-28

第1回 はじめてのSelenium

| 15:14

お久しぶりです。

御手洗です。

今日はSeleniumについて書きたいと思います。

Seleniumについては、滝川さんのラボメールを引用します。

Selenium(セレニウム)とは、オープンソースで開発されたWebアプリケーションテストツールです。


SeleniumではWebアプリケーションの操作を事前に登録しておくことで、これらの煩雑な作業を全て自動化することが可能で、また遷移後の画面に表示された内容も、単体テストツール同様に自動的にチェック・可視化して確認することが可能です。


エビデンス(テスト実行証明)として画面のスクリーンショットを個別に取得することも可能で、テスト実行後の報告作業も省力化して行うことができます。


テストの合間にデータベースの値を変更することもでき、また、FlashSilverlightといったプラグイン型のRIAのテストも行うことが、JavaScript連携機能を利用することで可能です。

こんな感じです。

わかりやすいですね。

これからこのブログSeleniumを使ってみて便利だったこと、大変だったこと、こうしたほうがよかったことなどをまとめていきたいと思います。

第1回 はじめてのSelenium

まずは、Selenium IDEで作成した簡単なテストケースを紹介したいと思います。

自分が、作ったSeleniumのコードはHTML形式となっています。

こんな感じです。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://localhost:8080/sa-struts-tutorial/" />
<title>AddSampleTestCase</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">AddSampleTestCase</td></tr>
</thead><tbody>
<tr>
	<td>open</td>
	<td>/sa-struts-tutorial/</td>
	<td></td>
</tr>
<tr>
	<td>clickAndWait</td>
	<td>link=足し算</td>
	<td></td>
</tr>
<tr>
	<td>type</td>
	<td>arg1</td>
	<td>20</td>
</tr>
<tr>
	<td>type</td>
	<td>arg2</td>
	<td>30</td>
</tr>
<tr>
	<td>clickAndWait</td>
	<td>submit</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>javascript{ this.getText(&quot;//form[@name='addActionForm']&quot;).substr(-2); }</td>
	<td></td>
</tr>
<tr>
	<td>verifyEval</td>
	<td>this.getText(&quot;//form[@name='addActionForm']&quot;).substr(-2);</td>
	<td>50</td>
</tr>

</tbody></table>
</body>
</html>

Webアプリケーションには、SAStrutsのサンプルアプリケーションを使用しました。

このSeleniumテストケースは、Selenium IDEブラウザの操作を記録していき、最後のechoとverifyEvalを追記し、HTML形式で保存しました。

Selenium IDEで実行するとこんな感じになります。

f:id:mitarai2009:20100428151401p:image

Selenium IDEを使用すると、HTML形式で保存したり、JUnit形式のソースコードなども出力できます。

それでは、簡単にソースの説明を行いたいと思います。


コンソール出力
<tr>
	<td>echo</td>
	<td>javascript{ this.getText(&quot;//form[@name='addActionForm']&quot;).substr(-2); }</td>
	<td></td>
</tr>

このコードは、画面の状態をコンソールや結果HTMLに出力する機能です。

Addアプリケーションでは、計算結果にタグが設定されていないので、addActionForm配下のテキストをすべて取得し、後ろから2文字を取得しています。

addActionForm配下という指定はXPathという記述方法です。

この記述は、ルート配下のformタグでname属性の値がaddActionFormとなっているタグを検索しています。

echoは、引数に指定された値を出力するだけのメソッドですが、javascript{}と書き、括弧の中にJavaScriptを追記すると、記述したJavaScriptの実行結果が出力されます。

あと、getTextメソッドですが、これはSeleniumAPIです。

Seleniumで実行したアプリケーションにはすべてSeleniumAPIが追加されます。

上記のようにどの画面からもSeleniumAPIを直接呼び出すことができます。


verifyチェック
<tr>
	<td>verifyEval</td>
	<td>this.getText(&quot;//form[@name='addActionForm']&quot;).substr(-2);</td>
	<td>50</td>
</tr>

次に、verifyチェックです。

Seleniumには、verifyメソッドとassertメソッドが用意されています。

verifyメソッドはチェックにエラーがあっても次の処理を実行しますが、assertメソッドはチェックにエラーがあるとその時点でテストが終了してしまいます。

なので、テスト検証のチェックにはverifyメソッドを利用し、失敗すると処理が継続できなそうなチェックはassertメソッドで実施するのが無難です。

では、中身を解説します。

verifyEvalメソッドは、対象として指定された文字列JavaScriptとして実行し、実行して返却された結果と値を比較します。

処理の内容は上記のechoと同じです。

ただし、これでは見難いし画面のレイアウトが変更されるといちいち変更しないといけません。

本来は、テストチェック対象の文字列をdivタグなどを使用してIDを振ると便利です。

<s:form>
<html:text property="arg1"/> +
<html:text property="arg2"/>
= <div id="result">${f:h(result)}</div><br />
<input type="submit" name="submit" value="サブミット"/>
</s:form>

こんな感じでコーディングしておくと、verifyEvalメソッドではなく、verifyTextメソッドを使用できるのでより簡単になります。

<tr>
	<td>verifyText</td>
	<td>result</td>
	<td>50</td>
</tr>

このようにテストチェック対象はすべてIDを振ったほうがレイアウト変更にも耐えられます。(当然、割り振ったIDが変更されないという前提ですが)

Seleniumを使ってテストの自動化を行いたいと思っている方は、コーディングの際になるべくIDを割り振るようにしてください。

本日は以上です。

それでは、また。

2010-03-26

Row展開処理メモ 第二弾-DataGridの仮想モードに注意

| 17:53

お久しぶりです。

御手洗です。

ずいぶんブログをご無沙汰してしまいました。

現場作業が落ち着いてきたので、不定期ではありますがブログの更新を再開したいと思います。

今回は、ずっと書きたかったDataGridの仮想モードについてです。

DataGridの仮想モードに注意

DataGridやListBoxなどには、仮想モードという機能が実装されています。

仮想モードとは、非常に大きな表形式のデータをDataGridに表示する際に、表示に必要な行のみインスタンスを作成し、必要になったらそのインスタンスを再利用するという機能です。*1

この機能自体はいいと思うのですが、現在のSilverlight3ではこの仮想モードをオフにすることができないのです。

そのおかげで苦労してCellの展開をできるように実装したDataGrid(前回の記事を参照)に問題が発生してしまいました。

問題とは以下の通りです。

まず、何個かCellを展開しておきます。

f:id:mitarai2009:20100326175044p:image

そしてスクロールします。

すると、展開してないはずのCellもスクロールされてしまいます。

f:id:mitarai2009:20100326175038p:image

f:id:mitarai2009:20100326175034p:image

これには、かなりハマりました。

いろいろなところにVirtualizationMode.Standardを設定しても全然この設定が有効になりませんでした。(VirtualizationModeの設定方法が間違えていたのかもしれませんが・・・)

そもそも、VirtualizationMode.Standardはこの仮想モードを無効にする設定ではないのでしょうか。

結局、無効にする方法はわからなかった(ソースも見れないし・・・)のでDataGridのスクロールバーを無効にして、ScollViewerをかぶせることによってこの問題を回避しました。

f:id:mitarai2009:20100326175028p:image

f:id:mitarai2009:20100326175026p:image

f:id:mitarai2009:20100326175024p:image

たかだか30行ぐらいの表示で仮想モードなんて使わなくてもいいのに、無理やり使わされるのはどうなんでしょう。

簡単に無効にするオプションもないし、できればSilverlight4では簡単に無効にするオプションをつけてほしいですね。

ちなみに、Cellを取得してVirtualizingStackPanelのイベントからインスタンスを随時生成する、なんてやり方をすればもしかしたらこの問題を解決できるのかもしれません。

しかし、無効にしたいだけなのにそんなコードを書かないといけないのは面倒ですよね。

できれば、プロパティで指定するだけで簡単に有効/無効にしたいです。

まとめ

DataGridやListBoxなどのコントロールには仮想モードという機能があるというのを頭に置いて開発したほうがよさそうです。

全然まとめられてないですが、今日はこの辺で。

ulnmbvkcseulnmbvkcse2014/12/03 18:27rnksynfejbgpsdfmbct, <a href="http://www.qyfholrlen.com/">kgncggjfnt</a> , [url=http://www.jspmrjzsyk.com/]viurciywqy[/url], http://www.jijegsukbg.com/ kgncggjfnt

2009-12-10

Row展開処理メモ 第一弾-DataGridの編集モードに注意

| 11:30

こんにちは。

御手洗です。

DataGridのRowを展開する処理を実装しました。

DataGridのRowを展開というのは以下のような画面です。

まずは、通常の画面。

f:id:mitarai2009:20091210112107p:image

このDataGridの初めのCellをクリックするとRowが展開されて明細行が表示されます。

f:id:mitarai2009:20091210112104p:image

こんな感じの画面を作ってみました。

ちょっと画面イメージは変わってしまいますが、RowDetailsTemplateを使っても行詳細を表示することができるので、こんなめんどくさいことやりたくないと思う方はそちらを利用してください。

参考URLhttp://msdn.microsoft.com/ja-jp/library/cc903938(VS.95).aspx

今回は、この画面を実装中に困ったことシリーズ第一弾(全二回)をブログに残しておこうと思います。

この処理は、一番最初のCellをクリックした際に、関係のあるCellの高さを変更しています。

private void OpenMonthlyReportGrid(
    DataGrid dataGrid,
    DataGridPreparingCellForEditEventArgs e,
    MonthlyReportItem item)
{
    e.Row.Height = 30 + (item.WorkTimeDetailList.Count * 32);
    item.ExpandFlag = true;
    Grid dateGrid = (Grid)dataGrid.Columns[0].GetCellContent(e.Row);
    dateGrid.RowDefinitions[1].Height = GridLength.Auto;

    Grid projectGrid = (Grid)dataGrid.Columns[1].GetCellContent(e.Row);
    projectGrid.RowDefinitions[1].Height = GridLength.Auto;

    Grid workTimeGrid = (Grid)dataGrid.Columns[2].GetCellContent(e.Row);
    workTimeGrid.RowDefinitions[1].Height = GridLength.Auto;

    Grid subTotalGrid = (Grid)dataGrid.Columns[3].GetCellContent(e.Row);
    subTotalGrid.RowDefinitions[1].Height = GridLength.Auto;
}

GetCellContentを使用して基底パネル(Gridパネル)を取得し、高さを変更しています。

閉じるほうはこんな感じ。

private void CloseMonthlyReportGrid(
    DataGrid dataGrid,
    DataGridPreparingCellForEditEventArgs e,
    MonthlyReportItem item)
{
    e.Row.Height = 30;
    dataGrid.RowHeight = 30;
    item.ExpandFlag = false;
    Grid dateGrid = (Grid)dataGrid.Columns[0].GetCellContent(e.Row);
    dateGrid.RowDefinitions[1].Height = new GridLength(0);

    Grid projectGrid = (Grid)dataGrid.Columns[1].GetCellContent(e.Row);
    projectGrid.RowDefinitions[1].Height = new GridLength(0);

    Grid workTimeGrid = (Grid)dataGrid.Columns[2].GetCellContent(e.Row);
    workTimeGrid.RowDefinitions[1].Height = new GridLength(0);

    Grid subTotalGrid = (Grid)dataGrid.Columns[3].GetCellContent(e.Row);
    subTotalGrid.RowDefinitions[1].Height = new GridLength(0);
}

ここで注意していただきたいのは以下の箇所です。

    dataGrid.RowHeight = 30;

この処理がないと、一度展開したRowの高さがそのままになってしまい、展開していない場合の高さに戻りません。

この処理があるだけで全体のRowの高さを展開していない場合の高さに戻せます。

この処理を行っても、既に展開しているRowの高さが変わることはありません。

多分、Rowの高さはDataGridRowクラスのHeightを優先しているからだと思いますが、今後実装が変わった場合(Silverlight4になる。など)動きが変わってしまうかもしれないので注意する必要がありますね。

今回ブログにメモしておきたかったのはこのことではありません。

その内容は以下に記載します。

DataGridの編集モードに注意

はじめ、この画面を実装したときにCellをクリックして高さを変更しているにも関わらず内部のGridパネルが変更してくれませんでした。

こんな感じになっちゃいます。

f:id:mitarai2009:20091210112731p:image

初めのCellが展開される前と変わっていないのがわかると思います。

自分が最初にハマったときとちょっと動きは違うのですが、原因は同じです。

原因はCellの編集モードにありました。

Cellクリックすると編集モードになります。

Rowの高さを変える処理もその編集モードになる際のイベントで処理を行っています。(自分がハマったときはBeginningEditイベントに処理を追加していました。)

編集モードになると編集モード用のDataTemplateを使用するのですが、今回は指定していなかったので問題なく動作するはずだと思っていました。

しかし、指定していなくても同じインスタンスのDataTemplateを使用しているのではなく、同じDataTemplateで別のインスタンスを利用しているみたいなんです。

なので、編集モード用のDataTemplateインスタンスが適用され、高さ変更がうまくいきませんでした。

これを解決するためにとった方法は、Cellの編集モードをキャンセルする方法です。

ReadOnlyにしてしまうと編集イベントが取れないのでこの方法にしました。

実装したソースは以下の通りです。

private void monthlyReportGrid_PreparingCellForEdit(
    object sender,
    DataGridPreparingCellForEditEventArgs e)
{
    DataGrid dataGrid = (DataGrid)sender;
    if (e.Column.DisplayIndex == 0)
    {
        dataGrid.CancelEdit();
        ExpandMonthlyReportGrid(dataGrid, e);
    }
}

BeginningEditイベントではキャンセル処理がうまく動作しなかったので、PreparingCellForEditイベントになっています。

編集モードに移行したCellが0番目だった場合(初めのCell)、DataGridのCancelEdit()メソッドで編集モードをキャンセルしています。

この後に、Rowの高さを変更するとうまく動作してくれました。

まとめ

ソースを調べていないのではっきりしたことは言えませんが、編集モードのDataTemplateを指定していなくても編集モードに切り替わると別のインスタンスになるので注意してください。




ということで、次回に続きます。

LhilLhil2012/03/23 04:58I'm not easliy impressed but you've done it with that posting.

jwrbtxjwrbtx2012/03/23 15:55QvGCzg <a href="http://fdsqbxvuohwc.com/">fdsqbxvuohwc</a>

chwhzuptchwhzupt2012/03/23 18:52uGrs7H , [url=http://zvyjjesojtgp.com/]zvyjjesojtgp[/url], [link=http://xrjmffqaogkt.com/]xrjmffqaogkt[/link], http://ttedrtjlooto.com/

2009-12-03

TreeViewのアイテムを起動時に選択する方法

| 11:40

こんにちは。

御手洗です。

今日は、TreeViewの続編です。

TreeViewのアイテムを起動時に選択する方法を記載します。

ItemTemplateを使用してTreeViewItemを自動生成する場合、IsSelected属性がXAMLでは指定できないのでLoadedイベントなどで実装します。

まずは、Loadedイベントのソースを見てみます。

private void TreeView_Loaded(object sender, RoutedEventArgs e)
{
    TreeView treeView = sender as TreeView;
    treeView.UpdateLayout();
    SelectApplicationTreeItem(treeView, treeView.Items, "aaaaa-001-002");
}

private bool SelectApplicationTreeItem(ItemsControl itemControl, IEnumerable collection, string selectName)
{
    foreach (TreeViewItemData treeDataItem in collection)
    {
        TreeViewItem treeViewItem = (TreeViewItem)itemControl.ItemContainerGenerator.ContainerFromItem(treeDataItem);
        if (treeViewItem == null) continue;
        if (selectName.Equals(treeDataItem.Name))
        {
            treeViewItem.IsSelected = true;
            return true;
        }
        else
        {
            if (treeDataItem.Children != null && treeDataItem.Children.Count != 0)
            {
                if (SelectApplicationTreeItem(treeViewItem, treeDataItem.Children, selectName)) return true;
            }
        }
    }
    return false;
}

TreeViewもしくは、TreeViewItemの子供のTreeViewItemを取得し、指定された名称のIsSelectedプロパティをtrueに変更しています。

実に簡単に見えるんですが、この作業に結構ハマりました。

なぜかというと、TreeViewItemは一度展開されないと生成されないので、ContainerFromItemメソッドでTreeViewItemを取得しようとしても必ずnullになってしまいます。

なので、IsSelectedプロパティをtrueにできませんした。

DataGridでもあったんですが(いずれブログに記載します)性能を考慮してるんでしょうが、アイテムを動的に生成する、または共有する仕組みがデフォルトで組み込まれているので、その処理が影響して上記のような簡単な作業でハマってしまいます。

データ量が多ければそのほうがいいと思いますが、データ量が少ないものに関しては最初に読み込んでもいいと思うんです。

なので、その機能を選べるようになっていればうれしいんですが、そうもなっていないようで・・・。

まあ、ないものねだりをしてもしょうがないので解決方法を記載します。

基本的は、一番上のTreeViewItemは取得できるのでIsExpandedプロパティをtrueにしてUpdateLayout()メソッドを実行(重要!!)すれば子供のTreeViewItemが生成されます。

その方法でもいいのですが、今回は起動時にツリーを全展開しておく手順を記載します。

<controls:TreeView Margin="5" Grid.Row="0"
    ItemTemplate="{StaticResource treeViewHierarchicalDataTemplate}"
    ItemsSource="{Binding TreeItemList, Mode=TwoWay}"
    Loaded="TreeView_Loaded">
    <controls:TreeView.ItemContainerStyle>
	    <Style TargetType="controls:TreeViewItem">
		    <Setter Property="IsExpanded" Value="true"/>
	    </Style>
    </controls:TreeView.ItemContainerStyle>
</controls:TreeView>

TreeViewのItemContainerStyleでIsExpandedプロパティをtrueにすることで全展開されます。

この記述をしておいて、TreeViewのUpdateLayout()を実行するとすべてのTreeViewItemが生成されています。

f:id:mitarai2009:20091203113955p:image

以上で完成です。

|