WPFのアプリをテストするときは躓きやすいのでちょっとコツを書きます。
こんな感じの構成のときどうやって操作していいのか最初はちょっと難しいですよね。
<NavigationWindow xClass="WpfAppSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlnslocal="clr-namespace:WpfAppSample"
mcIgnorable="d"
Title="MainWindow" Height="450" Width="800">
</NavigationWindow>
<Page xClass="WpfAppSample.SamplePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnslocal="clr-namespace:WpfAppSample"
mcIgnorable="d"
dDesignHeight="450" dDesignWidth="800"
Title="SamplePage">
<Grid>
<GridColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</GridColumnDefinitions>
<localSampleUserControl GridColumn="0">
</localSampleUserControl>
<Canvas GridColumn="1">
<TextBox Height="119" CanvasLeft="82" TextWrapping="Wrap" Text="{Binding Data}" CanvasTop="182" Width="224"/>
</Canvas>
</Grid>
</Page>
<UserControl xClass="WpfAppSample.SampleUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnslocal="clr-namespace:WpfAppSample"
mcIgnorable="d"
dDesignHeight="450" dDesignWidth="800">
<Canvas Background="#FFC9D6F6">
<ListView Height="368" Width="340" CanvasLeft="25" CanvasTop="56" ItemsSource="{Binding Users}">
<ListViewItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<CheckBox Content="Engineer" IsChecked="{Binding IsEngineer}"/>
</StackPanel>
</DataTemplate>
</ListViewItemTemplate>
</ListView>
<Button Content="Add" CanvasLeft="227" CanvasTop="28" Width="75" Click="Button_Click"/>
<TextBox Height="23" CanvasLeft="25" TextWrapping="Wrap" Text="{Binding Name}" CanvasTop="28" Width="120"/>
<CheckBox Content="Engineer" CanvasLeft="150" CanvasTop="30" Width="77" IsChecked="{Binding IsEngineer}"/>
</Canvas>
</UserControl>
ドライバを作る
まずはドライバを作ります。このサンプルだと以下に作ります。一つ一つ作っていくところがポイントですね。
- Window
- Page
- UserControl
- ItemsControlのItem
要素の特定
特定方法ですが、Windowを捕まえるのはWindowControlのメソッドを使います。これはWinFormsと同じですね。以下WindowsAppFriendに対する拡張メソッドにしていますが中身はWindowControlのstaticメソッドです。
var win = app.WaitForIdentifyFromTypeFullName("WpfAppSample.MainWindow");
それで、Window以下に関しては、x:nameでアクセスできるならWinFormsの時と同じくフィールドを使ってもらえばいいのですが、ついていない場合はVisualTreeをだどって見つけます。前に書いてたのでそのリンクを貼っておきます。
ishikawa-tatsuya.hatenablog.com
ishikawa-tatsuya.hatenablog.com
ドライバのサンプル
using Codeer.Friendly.Windows;
using Codeer.Friendly.Windows.Grasp;
namespace Driver.Windows
{
public class MainWindowDriver
{
public WindowControl Core { get; }
public MainWindowDriver(WindowControl core)
{
Core = core;
}
}
public static class MainWindowDriverExtensions
{
public static MainWindowDriver AttachMainWindow(this WindowsAppFriend app)
=> new MainWindowDriver(app.WaitForIdentifyFromTypeFullName("WpfAppSample.MainWindow"));
}
}
using Codeer.Friendly;
using Codeer.Friendly.Dynamic;
using RM.Friendly.WPFStandardControls;
namespace Driver.Windows
{
public class SamplePageDriver
{
public WPFUserControl Core { get; }
public WPFTextBox TextBox => Core.LogicalTree().ByBinding("Data").Single().Dynamic();
public SamplePageDriver(AppVar core)
{
Core = new WPFUserControl(core);
}
}
public static class SamplePageDriverExtensions
{
public static SamplePageDriver AttachSamplePage(this MainWindowDriver window)
=> window.Core.VisualTree().ByType("WpfAppSample.SamplePage").Single().Dynamic();
}
}
using Codeer.Friendly;
using Codeer.Friendly.Dynamic;
using RM.Friendly.WPFStandardControls;
using System.Windows.Controls;
namespace Driver.Windows
{
public class SampleUserControl_Driver
{
public WPFUserControl Core { get; }
public WPFListView ListView => Core.LogicalTree().ByBinding("Users").Single().Dynamic();
public WPFButtonBase Add => Core.LogicalTree().ByType<Button>().ByContentText("Add").Single().Dynamic();
public WPFTextBox TextBox => Core.LogicalTree().ByBinding("Name").Single().Dynamic();
public WPFToggleButton Engineer => Core.LogicalTree().ByBinding("IsEngineer").Single().Dynamic();
public SampleUserControl_Driver(AppVar core)
{
Core = new WPFUserControl(core);
}
}
public static class SampleUserControlDriverExtensions
{
public static SampleUserControl_Driver Attach_SampleUserControl(this SamplePageDriver page)
=> page.Core.VisualTree().ByType("WpfAppSample.SampleUserControl").Single().Dynamic();
}
}
using Codeer.Friendly;
using Codeer.Friendly.Dynamic;
using RM.Friendly.WPFStandardControls;
namespace Driver.Windows
{
public class UserListViewItemDriver
{
public WPFUserControl Core { get; }
public WPFTextBlock TextBlock => Core.VisualTree().ByBinding("Name").Single().Dynamic();
public WPFToggleButton Engineer => Core.VisualTree().ByBinding("IsEngineer").Single().Dynamic();
public UserListViewItemDriver(AppVar core)
{
Core = new WPFUserControl(core);
}
}
public static class UserListViewItemDriverExtensions
{
public static UserListViewItemDriver AsUser(this WPFListViewItem item)
=> new UserListViewItemDriver(item.AppVar);
}
}
シナリオのサンプル
using System.Diagnostics;
using Codeer.Friendly.Windows;
using Driver;
using NUnit.Framework;
using Driver.Windows;
namespace Scenario
{
[TestFixture]
public class Test
{
WindowsAppFriend _app;
[SetUp]
public void TestInitialize() => _app = ProcessController.Start();
[TearDown]
public void TestCleanup() => Process.GetProcessById(_app.ProcessId).Kill();
[Test]
public void TestMethod()
{
var mainWindow = _app.AttachMainWindow();
var samplePage = mainWindow.AttachSamplePage();
var sampleUserControl = samplePage.AttachSampleUserControl();
var item = sampleUserControl.ListView.GetItem(1);
var userItem = item.AsUser();
userItem.Engineer.EmulateCheck(true);
}
}
}
もっと複雑なのは?
おそらく操作する対象を特定するのが難しいのだと思います。これ以上複雑な場合はFriendlyの基本機能、「対象プロセスのAPIをなんでも使える」というのを使って最適な特定方法を作ってみてください。その場合、必要なのはFriendlyの知識ではなくWPFの知識だったりします。頑張ってください!