【问题标题】:WPF - Raise KeyEvent Trigger in a Unit Test does not workWPF - 在单元测试中引发 KeyEvent 触发器不起作用
【发布时间】:2012-11-30 07:46:47
【问题描述】:

我想在单元测试中引发一个关键事件。当按下某个键时,TextBox 的文本属性中应包含按下的键。

这是一个使用 Xunit 的最小工作示例:

[TemplatePart(Name = Field0Name, Type = typeof(TextBox))]
class MyControl : Control
{
    public const string Field0Name = "Field0";
}

public class MyControlTests
{
    private MyControl control;
    public MyControlTests()
    {
        MemoryStream ms = new MemoryStream();
        StreamWriter sw = new StreamWriter(ms);
        sw.Write(@"<ControlTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                        <Grid>
                            <TextBox Name='Field0'/>
                        </Grid>
                    </ControlTemplate>");
        sw.Flush();
        ms.Position = 0;

        control = new MyControl() { Template = (ControlTemplate)XamlReader.Load(ms) };
        control.ApplyTemplate();
    }

    [Fact]
    public void Field0Name_PreviewKeyDownEvent_WriteLetter()
    {
        TextBox tb = (TextBox)control.Template.FindName(MyControl.Field0Name, control);
        FocusManager.SetFocusedElement(control, tb);

        tb.RaiseEvent(new KeyEventArgs(Keyboard.PrimaryDevice, new FakePresentationSource(), Environment.TickCount, Key.A)
        {
            RoutedEvent = TextBox.PreviewKeyDownEvent
        });

        Assert.Equal("a", tb.Text);
    }
}

public class FakePresentationSource : PresentationSource
{
    protected override CompositionTarget GetCompositionTargetCore()
    {
        return null;
    }

    public override Visual RootVisual { get; set; }

    public override bool IsDisposed { get { return false; } }
}

Generic.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TextBoxRaiseEventProject">
<Style TargetType="{x:Type local:MyControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <Grid>
                        <TextBox x:Name="Field0"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

测试报告:

【问题讨论】:

  • 你到底想测试什么?从您的代码示例来看,您似乎正在尝试测试 WPF TextBox 控件是否接受键盘输入。
  • @AbeHeidebrecht 也许是为了测试绑定是否正常工作。
  • 我在文本框上注册了 PreviewKeyDownEvent 并过滤了一些输入。我想测试其他输入是否未被过滤。
  • 如果@AbeHeidebrecht 是正确的,那么你肯定不想对微软的代码进行单元测试:) 我认为虽然你从一个错误的角度来测试你想要测试的东西? ..为您发布差异方法。

标签: c# wpf unit-testing controls keyevent


【解决方案1】:

此回复不是您希望或可能一直期待的您的问题。然而我认为它是正确的,我希望你在阅读后重新考虑你的单元测试方法。

我认为在单元测试中调用按钮单击并不是对功能进行单元测试的最佳方法。这是 MVVM、MVC、MVP 等模式的原因之一。您希望创建一个与 UI 使用分离的可测试类。 (我很抱歉,因为我不想让它听起来像一个讲座)。

因此,在您的示例中,我要做的是创建一个命令,将其绑定到按钮以供使用,然后通过调用将触发一些可测试组件/部分的命令来进行单元测试。

<Button Command="{Binding PushButtonCommand}"..

some class MyClass
{
    public ICommand PushButtonCommand
    {
        get
        {
           return _pushButtonCommand ??
                (_pushButtonCommand = new DelegateCommand(ExecutePushButton));
        }
     }

    private void ExecutePushButton()
    {
         //lets pretend it sets some property that you need to test;
         NeedBacon = true;   
    }

现在这是可测试的。在创建类后的单元测试中,触发命令 并检查属性:

Assert.IsFalse(myClassInstance.NeedBacon);
((DelegateCommand)myClassInstance.PushButtonCommand).Execute(null);
Assert.IsTrue(myClassInstance.NeedBacon);

【讨论】:

  • OP 尝试对自定义控件进行单元测试。控件后面没有视图模型。该控件也不是Button控件而是一个花哨的Textbox,它应该如何使用命令?
  • 听起来你们可能需要研究自动化而不是单元测试。您可以使用 .NET 中的自动化库来调用各种控制行为。
  • 你能发布一个使用自动化模拟按键的小例子吗?
猜你喜欢
  • 1970-01-01
  • 2013-01-05
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 2021-08-04
相关资源
最近更新 更多