Windowsデスクトップアプリ(WPF)のE2Eテストを書きたくて、Friendlyに出会った。これが個人的に最も直感的だった。
詰まった点としては、Friendlyというより、WPFのLogicalTreeとVisualTreeの挙動というところにあると思われるので、同じこと悩んでる人がいたらいいなと思って、書きます。
メニューを動的に組んでいるケースでハマった
ログイン者に応じて、メニューを動的に切り替える仕組みを採用していて、そのXAMLがこんな感じです。
MainWindow.xaml
<Grid Background="#FFF2F0DF">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu ItemsSource="{Binding GlobalMenu}">
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding DataContext.NavigateCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type view:MainWindow}}}"/>
<Setter Property="CommandParameter" Value="{Binding Value}"/>
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MainMenuModel}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Text}"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
<ContentControl prism:RegionManager.RegionName="ContentPage" Grid.Row="1" />
</Grid>
システムを起動した直後は、GlobalMenu
はnull
なので、LogicalTreeには何も無い。Bindingによって、GlobalMenu
に値がセットされると、階層構造に従ったメニューが構成されます。HierarchicalDataTemplate
がそれで、値をバインドすればこういうメニューが作られます。
├── メニューA
├── メニューA1
├── メニューA2
├── メニューA3
├── メニューB
├── メニューB1
├── メニューB2
├── メニューB3
├── メニューC
├── メニューC1
├── メニューC2
├── メニューC3
この「メニューA1」等をクリックしたくて、試行錯誤したコードがこれ。
[TestClass]
public class MenuTest
{
private WindowsAppFriend _app;
private WindowControl w;
[TestInitialize]
public void TestInitialize()
{
var path = System.IO.Path.GetFullPath("hoge.exe");
_app = new WindowsAppFriend(Process.Start(path));
w = _app.FromZTop();
}
[TestMethod]
public void Testメニュー開け()
{
AppVar main = _app.Type<Application>().Current.MainWindow;
var globalmenu = main.VisualTree().ByType<MenuItem>(); //Countすると3
new WPFMenuItem(globalmenu[0]).EmulateClick(); //メニューAがクリックされる
var uuum = globalmenu[0].visualTree().ByType<MenuItem>().Count; //これが0になるのが辛い
}
}
}
親のメニュー(メニューA,メニューB,メニューC)は、VisualTree
を辿ったら取れるのに、子供のMenu
が取れないのはなんでなんだろう。
とりあえずなんですけど、VMから直接コマンド飛ばして逃げたが、良くないねこれは。
var hoge = main.Dynamic().DataContext; //MainViewModelのVM
hoge.NavigateCommand.Execute("Page1");
キーイベント関係をどうしよう
ボタンを押すサンプルが転がっているが、キーイベント関連があまりなかった。
このコードで出来たんだけど、いいのかな。何か間違ってないよね。
System.Windows.Forms.SendKeys.SendWait("{ENTER}");
- テキストボックスのReturnキー押下
- モーダルで上げたWindowのボタン押下
- DataGridのセル内キーイベント押下と右クリック
- DataGridにチェックを付ける
コードでUIが操作できると楽しいので、がんばる。