从单元测试项目启动并调用 WPF 应用程序上的方法

2023-12-24

我想启动一个 WPF 应用程序并调用 ViewModel 上的方法来控制该应用程序以进行集成测试。就像是:

    [Test]
    public void Test1()
        var application = new MyApp();
        application.InitializeComponent();
        application.Run();

(好的,这会在此时停止测试执行,大概会将控制权传递给 WPF 应用程序。不知道如何处理这个问题。在单独的线程或其他线程中启动?)

然后我希望能够在 ViewModel 上获取和设置值,如下所示:

        application.MyViewModel.SomeProperty = "A value!";

这里的目标是在集成意义上测试 WPF 应用程序,而不是求助于 WinAppDriver、White、CodedUI 或类似的任何混乱的东西。有想法吗?


您要么需要一个单独的线程来操作视图模型,要么需要在调度程序线程中执行代码来执行此操作。我更喜欢后者,但两者都可以。前者需要您小心地使用调度程序将某些操作封送到 UI 线程;后者需要您小心谨慎。视图模型属性更改不需要这样做,因为 WPF 会自动为您执行此操作,但其他操作(例如直接调用 UI 对象方法) - 例如Window.Close() — do.

以下是您可以使用调度程序线程执行所有测试代码的示例:

[TestMethod]
public void TestWpfApp()
{
    Thread thread = new Thread(() =>
    {
        var application = new App();
        Application.ResourceAssembly = System.Reflection.Assembly.GetExecutingAssembly();
        application.InitializeComponent();
        application.Dispatcher.InvokeAsync(() =>
        {
            _TestApplication(application);
        }, System.Windows.Threading.DispatcherPriority.ApplicationIdle);
        application.Run();
    });

    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();
}

private static async void _TestApplication(Application application)
{
    Window window = application.MainWindow;
    ViewModel viewModel = (ViewModel)window.DataContext;

    await Task.Delay(TimeSpan.FromSeconds(5));
    viewModel.Text = "Hello World!";
    await Task.Delay(TimeSpan.FromSeconds(5));
    window.Close();
}

基本结构是设置一个适合运行 WPF UI 的线程(它必须是 STA 线程,并且您不应该弄乱单元测试的线程,因此需要为此目的创建一个新线程),并且然后在该线程中,通过以下方式执行通常的 WPF 设置和队列InvokeAsync()向调度程序调用主测试方法,使其在 WPF 代码开始运行后开始执行。

当然,这个例子假设ViewModel类与Text属性和主窗口的DataContext属性设置为此的实例ViewModel。在我的示例程序中,我只是绑定了Text财产给一个TextBlock.Text财产。显然,您可以对视图模型做任何您想做的事情。

请注意,我必须明确设置Application.ResourceAssembly。在我目前使用的 Visual Studio Community 2017 中,单元测试框架在以下上下文中运行文本:Assembly.GetEntryAssembly()回报null,这会破坏 WPF 的资源加载。明确设置它可以解决这个问题(我正在使用Assembly.GetExecutingAssembly(),因为我将单元测试代码与示例 WPF 程序放在同一个程序集中……显然,如果将它们保留在不同的程序集中,则必须以其他方式找到正确的程序集)。

在我的测试中,使用System.Windows.Threading.DispatcherPriority.ApplicationIdle在通话中Dispatch.InvokeAsync()没有严格要求。我找到了MainWindow and DataContext属性初始化良好。但我更喜欢明确地等待ApplicationIdle,只是为了确保这些已完全初始化,并且 WPF 程序本身已准备好开始接受您想要进行测试的任何输入。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从单元测试项目启动并调用 WPF 应用程序上的方法 的相关文章

随机推荐