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

ささいなことですが。

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

Friendly ハンズオン7 WinForms用上位ライブラリ

久しぶりのハンズオンです。
今回はWinForms用のラッパーライブラリであるFriendly.FormsStandasrdControlsに関して練習してみます。
Friendly.FormsStandasrdControlsはONIGIRI-SOFT(Windows&iPhoneアプリ開発)さんと協力して作りました。

対応表

System.Windows.Forms Ong.FormsStandardControls
Button FormsButton
CheckBox FormsCheckBox
CheckdListBox FormsCheckedListBox
ComboBox FormsComboBox
DataGridView FormsDataGridView
DateTimePicker FormsDateTimePicker
LinkLabel FormsLinkLabel
ListBox FormsListBox
ListView FormsListView
ListViewItem FormsListViewItem
ListViewSubItem FormsListViewSubItem
MonthCalender FormsMonthCalendar
NumericUpDown FormsNumericUpDown
ProgressBar FormsProgressBar
RadioButton FormsRadioButton
RichTextBox FormsRichTextBox
TabControl FormsTabControl
TextBox FormsTextBox
ToolStrip FormsToolStrip
ToolStripButton FormsToolStripButton
ToolStripComboBox FormsToolStripComboBox
ToolStripItem FormsToolStripItem
ToolStripTextBox FormsToolStripTextBox
TreeView FormsTreeView
TreeNode FormsTreeNode

こんな感じで大体は対応しています。
APIリファレンスです。
Ong.Friendly.FormsStandardControls.dll - 株式会社Codeer (コーディア)

コードはこちらからダウンロードできます。
ShinichiIshizuka/Ong.Friendly.FormsStandardControls · GitHub

ポリシーは「使用頻度の高いコントロール」の「使用頻度の高い操作」をラップすることです。
インターフェイスはシンプルに保たれ、使い勝手が良いことを目指しています。
このポリシーになっているのは、基本をFriendlyで作っているので簡単にユーザーで拡張ができるからですね。

ポイント

コンストラクタに中身を渡す

var checkBox = new FormsCheckBox(_form._checkBox);

これだけです。
あとはインテリセンスが使い方を教えてくれます。

操作したい場合はEmulateXXX

checkBox.EmulateCheck(CheckState.Checked);

操作系のメソッドは全てこの命名規則に従っています。
ラップした後、その変数の後にドットを打ってEmulateって打つと、おそらく希望の操作をインテリセンスが教えてくれます。

ハンズオンの練習用プロジェクト

ココからダウンロードしてください。
Ishikawa-Tatsuya/HandsOn7 · GitHub
右下のダウンロードボタンですね。
f:id:ishikawa-tatsuya:20141229145651p:plain

あ、ブロックの解除も忘れずに。
f:id:ishikawa-tatsuya:20141229145705p:plain

ではプロジェクトを開いて、ビルドしてみましょう。
Project/HandsOn7.sln

起動するとこんな画面です。
あ、一個だけイベント実装していて、ボタンを押すと、Clickedってボタンのテキストが変わります。
f:id:ishikawa-tatsuya:20141229145723p:plain

で、テストプロジェクトの方は既に参照設定とusingまでやっています。
ハンズオンじゃなくて本当に自分のテストを作るときは、NugetからFriendly.FormsStandardControlsをダウンロードしてください。
Friendly、Friendly.Windows、Friendly.Windows.Graspは一緒に落ちてきます。
f:id:ishikawa-tatsuya:20141229150112p:plain

最終的には参照はこんな感じになっています。
f:id:ishikawa-tatsuya:20141229163802p:plain

usingです。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Codeer.Friendly;
using Codeer.Friendly.Dynamic;
using Codeer.Friendly.Windows;
using System.Diagnostics;
using System.Windows.Forms;
//↓これがポイント
using Ong.Friendly.FormsStandardControls;

それから、操作対象のアプリには次のようにフィールドが定義されています。

private CheckBox _checkBox;
private ComboBox _comboBox;
private Button _button;
private TreeView _treeView;
private ListView _listView;

操作コードの練習に集中してもらうために、その他は用意しています。

では、始めましょう!

CheckBox

手始めにCheckBoxからいきますかー。これは雑魚ですね。チョイチョイです。
FormsCheckBoxでラップしてください。
コンストラクタにフィールドを渡せばよいですね。

[TestMethod]
public void CheckBoxTest()
{
    var checkBox = new FormsCheckBox(_form._checkBox);
}

Friendlyの基本部分を理解していれば、これが何をしているか分かりますね。
相手プロセスの中にあるCheckBoxのインスタンスをフィールドから取ってきて、それを渡しているのです。
では、チェック状態を変更してみましょう。
.Emulateって打ち込むとインテリセンスが教えてくれます。
EmulateCheckですね。
これ、ポイントはCheckState.Checkedを渡しています。「クリック」とかじゃなくて明確にコントロールの状態をしていするのですね。CheckBoxがスリーステイト対応ならIndeterminateも指定できます。
変更して、状態を確認するコードを書いてみましょう。

[TestMethod]
public void CheckBoxTest()
{
    var checkBox = new FormsCheckBox(_form._checkBox);
    checkBox.EmulateCheck(CheckState.Checked);
    Assert.AreEqual(CheckState.Checked, checkBox.CheckState);
}

では、実行してみます。分かりやすいように関数先頭にブレイクポイントを貼って、画面を見ながらステップ実行してみましょう。
f:id:ishikawa-tatsuya:20141229153101p:plain

ComboBoxとButton

ComboBoxとButtonです。一緒に書きます。<手抜きか
まあ、これはコード見たらわかると思います。
でも、実行してみてくださいねー。

[TestMethod]
public void ComboBoxTest()
{
    var comboBox = new FormsComboBox(_form._comboBox);
    comboBox.EmulateChangeSelect(2);
    Assert.AreEqual(2, comboBox.SelectedItemIndex);
}

[TestMethod]
public void ButtonTest()
{
    var button = new FormsButton(_form._button);
    button.EmulateClick();
    Assert.AreEqual("Clicked", button.Text);
}

ListView

今までのコントロールは、まあ操作できて当然?ですよねー。
ちょっと面倒なやつやってみます。
ListViewです。面倒ですね。僕はこれ嫌いですw。普通に仕事でお客さんがこれ使って欲しそうなこと言うと、使わない方向に誘導します。<おい
だって、そもそものコントロールの仕様からして複雑なんだもの。
そんな面倒なコントロールでもFriendlyを使うと簡単に操作できます。
まずは選択を変更してみましょう。

[TestMethod]
public void ListViewSelectTest()
{
    var listView = new FormsListView(_form._listView);
    listView.EmulateChangeSelectedState(1, true);

    //選択を変更する
    Assert.AreEqual(1, listView.SelectIndexes.Length);
    Assert.AreEqual(1, listView.SelectIndexes[0]);
}

ListViewは複数選択が可能ですね。だからインターフェイスはこんな感じです。

じゃあ、次はラベルを編集してみましょう。

[TestMethod]
public void ListViewEditTest()
{
    var listView = new FormsListView(_form._listView);

    //ラベルを編集する
    var item1 = listView.GetListViewItem(1);
    item1.EmulateEditLabel("abc");
    Assert.AreEqual("abc", item1.Text);
}

どうでしょうか?
編集のような複雑な操作も簡単書けるようになっています。

その他、こんなのも用意しています。

[TestMethod]
public void ListViewTest()
{
    var listView = new FormsListView(_form._listView);

    //現在の表示モードを取得する
    Assert.AreEqual(View.Details, listView.ViewMode);

    //サブアイテムの文字列を取得する
    Assert.AreEqual("0_2", listView.GetListViewItem(0).GetSubItem(2).Text);
}

TreeView

TreeViewもやってみましょう。
これを操作するためには二つのGUIアイテムを理解する必要があります。
TreeViewとTreeNodeですね。
f:id:ishikawa-tatsuya:20141229162229p:plain
まずは、目的のノードを取得する処理です。

[TestMethod]
public void TreeFindeItemTest()
{
    var treeView = new FormsTreeView(_form._treeView);
    //文字列から検索
    var node = treeView.FindItem("0", "0_0", "0_0_0");
    Assert.AreEqual("0_0_0", node.Text);
}

これは、表示されたテキストから検索しています。各階層ごとに検索文字列を渡しているわけです。

実は他にもノードを取得する方法があります。
インデックスから特定する方法と名前から特定する方法です。
両方とも各階層ごとに特定するためのインデックスや名前を渡していますね。

[TestMethod]
public void TreeGetItemIndexTest()
{
    var treeView = new FormsTreeView(_form._treeView);
    //インデックスから特定
    var node = treeView.GetItem(0, 0, 0);
    Assert.AreEqual("0_0_0", node.Text);
}
[TestMethod]
public void TreeGetItemNameTest()
{
    var treeView = new FormsTreeView(_form._treeView);
    //Nameから特定
    var node = treeView.GetItem("_node0", "_node0_0", "_node0_0_0");
    Assert.AreEqual("0_0_0", node.Text);
}

状況に合わせて使い分けてください。
では選択してみましょう。

[TestMethod]
public void TreeSelectTest()
{
    var treeView = new FormsTreeView(_form._treeView);
    var node = treeView.FindItem("0", "0_0", "0_0_0");
    treeView.EmulateNodeSelect(node);
    Assert.AreEqual("0_0_0", treeView.SelectNode.Text);
}

これもラベルを編集してみます。

[TestMethod]
public void TreeEditTest()
{
    var treeView = new FormsTreeView(_form._treeView);
    var node = treeView.FindItem("0", "0_0", "0_0_0");

    node.EmulateEditLabel("abc");
    Assert.AreEqual("abc", node.Text);
}

雰囲気つかめましたか?

だいたいこんな感じです。他のもこのノリで使ってみてください。これで、WinFormsのコントロールは大体操作できるようになったと思います。あと、基本部分のハンズオンも終わってるので、足りない部分の拡張も多分自分でできるようになっているはずです。
でも、GUI操作のためには、もう少し必要な技術があります。それは画面特定です。次回はそのためのライブラリFriendly.Windows.Graspをやります。