ささいなことですが。

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

Friendly ハンズオン 11 WPF用上位ライブラリ

今回はWPFGUIコントロールの操作です。
これは、めとべやさんと協力して作っています。ソースコードはこちらです。
Roommetro/Friendly.WPFStandardControls · GitHub

現在以下のものに対応しています。
WPF用は近いうちに機能追加していこうと思っています。
追加したらまたブログに書きますねー。

対応表

System.Windows.Controls Friendly.WPFStandardControls
ButtonBase WPFButtonBase
ComboBox WPFComboBox
ListBox WPFListBox
ListView WPFListView
MenuBase WPFMenuBase
MenuItem WPFMenuItem
ProgressBar WPFProgressBar
RichTextBox WPFRichTextBox
Selector WPFSelector
Slider WPFSlider
TabControl WPFTabControl
TextBox WPFTextBox
ToggleButton WPFToggleButton
TreeView WPFTreeView
TreeViewItem WPFTreeViewItem
Calendar WPFCalendar
DatePicker WPFDatePicker
DataGrid WPFDataGrid

※System.Windows.Controls.Primitivesのクラスも混じっています。

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

こちらからダウンロードお願いします。
Ishikawa-Tatsuya/HandsOn11 · GitHub

ビルドして対象アプリを起動すると、こんな感じです。
OKボタンを押すと、入力内容がメッセージボックスに表示されます。
f:id:ishikawa-tatsuya:20150110104756p:plain

DataGridの中には、このデータがリストで入っています。

public enum Language
{
    C,
    CPP,
    CS
}

[Serializable]
public class Member
{
    public string Name { get; set; }
    public Language Language { get; set; }
    public bool IsProgramer { get; set; }

    public override string ToString()
    {
        return Name + ", " + Language + ", " + IsProgramer;
    }
}

Testプロジェクトは参照設定も終わっています。
自分のテストプロジェクトで使う場合は、NugetからFriendly.WPFStandardControlsとFriendly.Windows.NativeStandardControlsを取得してください。NativeStandardControlsはメッセージボックス操作に使います。前回も書きましたが、WPFでもメッセージボックスはネイティブのものが使われているのです。

WPFTest.csコードはこれです。これに、書き足していってください。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Codeer.Friendly;
using Codeer.Friendly.Dynamic;
using Codeer.Friendly.Windows;
using Codeer.Friendly.Windows.NativeStandardControls;
using RM.Friendly.WPFStandardControls;
using System.Diagnostics;
using System.Windows;
using WpfTarget;
using Codeer.Friendly.Windows.Grasp;

namespace Test
{
    [TestClass]
    public class WPFTest
    {
        WindowsAppFriend _app;
        dynamic _main;

        [TestInitialize]
        public void TestInitialize()
        {
            _app = new WindowsAppFriend(Process.Start("WpfTarget.exe"));
            _main = _app.Type<Application>().Current.MainWindow;
        }

        [TestCleanup]
        public void TestCleanup()
        {
            Process.GetProcessById(_app.ProcessId).CloseMainWindow();
        }
    }
}

ハンズオン開始

TextBox

まずはTextBoxです。使い方はWinFormsのものと同じですね。
TextBoxの特定はx:Nameでやっています。テスタビリティーを上げるためにプロダクトの方で、全てのコントロールには名前を付けているのですね。

[TestMethod]
public void TestTextBox()
{
    var _textBoxCompanyName = new WPFTextBox(_main._textBoxCompanyName);
    _textBoxCompanyName.EmulateChangeText("Codeer.ltd");
    Assert.AreEqual("Codeer.ltd", _textBoxCompanyName.Text);
}

DatePicker

はい。DatePickerも簡単に操作できますね。

[TestMethod]
public void TestDatePicker()
{
    var _dateTimePickerFounding = new WPFDatePicker(_main._dateTimePickerFounding);
    _dateTimePickerFounding.EmulateChangeDate(new DateTime(2011, 3, 14));
    Assert.AreEqual(new DateTime(2011, 3, 14), _dateTimePickerFounding.SelectedDate);
}

DataGrid

DataGridです。編集方法はText、ComoboBox、CheckBoxに対応しています。その他のものが必要であれば、そんなに難しくはないので、各自で対応してみてください。(基本部分押さえていれば出来ると思います。)
データの検証はここでは、対応するデータでやっていますね。セル文字列を取るインターフェイスもあるのですが、こっちの方が手っ取り早いので。
WPFDataGridのthis[index]はdynamicで相手プロセスの参照が返ってきます。それを実データにキャストすることによって、相手プロセスからコピーを転送してきているのですね。

[TestMethod]
public void TestDataGrid()
{
    var _grid = new WPFDataGrid(_main._grid);
    _grid.EmulateChangeCellText(0, 0, "ishikawa");
    _grid.EmulateChangeCellComboSelect(0, 1, 2);
    _grid.EmulateCellCheck(0, 2, true);

    //1つめのデータアイテムのコピーを取得
    Member member = _grid[0];
    Assert.AreEqual("ishikawa", member.Name);
    Assert.AreEqual(Language.CS, member.Language);
    Assert.AreEqual(true, member.IsProgramer);
}

Button

ボタン操作です。OKボタンを押すと入力内容がメッセージボックスに表示されます。値の設定は、ここまでに書いたものを使い回しています。
表示されるメッセージボックスはWPFでもWin32のものですね。NativeMessageBoxを使用して操作します。

[TestMethod]
public void TestButtonBaseAndMessageBox()
{
    //値の設定
    TestTextBox();
    TestDatePicker();
    TestDataGrid();

    //非同期処理でボタンを押す
    var _buttonOK = new WPFButtonBase(_main._buttonOK);
    Async a = new Async();
    _buttonOK.EmulateClick(a);

    //メッセージボックス(ネイティブ)
    var window = new WindowControl(_main);
    var msg = new NativeMessageBox(window.WaitForNextModal());
    Assert.AreEqual("Codeer.ltd\r\n2011/03/14\r\nishikawa, CS, True", msg.Message);
    msg.EmulateButtonClick("OK");

    //非同期処理完了待ち
    a.WaitForCompletion();
}

GUI要素の特定は?

それはもうx:Nameが一番確実ですw
テスタビリティーを向上させることを考えればx:Nameを付けるのも、なんら恥じることはありません!
・・・
でもまあ嫌な人もいますよね。

Bindingから特定してみる。

結局ですね、相手プロセスでできることは全て可能なのです。だから特定方法も好きなように作ってもらえばOKです。で、その一例としてBindingから特定するサンプルを作ってみました。

コードはこちらから
Ishikawa-Tatsuya/Friendly-SearchByBinding · GitHub
これは、もう少し洗練させて、Friendly.WPFStandardControlsに取り込もうと思っています。乞うご期待!

自分で好きに作れます。

繰り返しますが、特定方法はFriendlyの基本部分とWPFを理解していれば好きなように作れます。
何かいい方法思いついた人はプルリクお願いします。
このブログへのコメントでもOKです!
イデア、要望レベルでも構いません。よろしくです。

次回はTestAssistantの話です。