63

使用带有MVC / MVP架构的 win 表单,我通常会使用一个类来包装视图以测试 UI,同时为模型和控制器/演示器使用模拟。包装类将通过属性和事件使 UI 中的大多数内容成为测试运行器的可观察属性。

这是测试 WPF 应用程序的可行方法吗?有没有更好的办法?有什么需要注意的问题吗?

4

9 回答 9

62

至于测试本身,您可能最好使用UI 自动化框架。或者,如果您想要更流畅且独立于 wpf/winforms/win32/swt 的框架使用方式,您可以从 Codeplex 下载White(前提是您能够在您的环境中使用开源代码)。

对于陷阱;如果您尝试测试您的视图,您可能会遇到一些线程问题。例如,如果您正在运行 NUnit,默认的 testrunner 将在 MTA(多线程 Appartment)中运行,而 WPF 需要作为 STA(单线程 Appartment)运行。Mike Two在单元测试 WPF 方面非常容易上手,但没有考虑线程问题。Josh Smith 在这篇文章中对线程问题有一些想法,他还指出了 Chris Hedgate 的这篇文章。Chris 使用 Peter Provost 的CrossThreadTestRunner的修改版本以更友好的方式包装 MTA/STA 问题。

于 2008-09-23T09:41:59.243 回答
13

2016 更新:使用免费的 TestStack.White 框架来自动化 WPF UI 测试

  • Project White 已被放弃,但它的继任者TestStack.White可通过 NuGet 包获得。
  • TestStack.White 具有用于启动 WPF 应用程序查找窗口/用户控制元素单击按钮/元素、模拟鼠标和键盘事件、等待等的实用方法。
  • 将启动 WPF 应用程序、单击按钮并检查结果的示例如下所示:

    using TestStack.White;
    using TestStack.White.UIItems;
    using TestStack.White.Factory;
    
    [TestMethod]
    public void TestDoSomething()
    {
        //Opens the app
        var app = Application.Launch("MyApp.exe");
    
        //Finds the main window (this and above line should be in [TestInitialize])
        var window = app.GetWindow("My App Window Title", InitializeOption.NoCache);
    
        //Finds the button (see other Get...() methods for options)
        var btnMyButton = window.Get<Button>("btnMyButtonWPFname");
    
        //Simulate clicking
        btnMyButton.Click();
    
        //Gets the result text box 
        //Note: TextBox/Button is in TestStack.White.UIItems namespace
        var txtMyTextBox = window.Get<TextBox>("txtMyTextBox");
    
        //Check for the result
        Assert.IsTrue(txtMyTextBox.Text == "my expected result");
    
        //Close the main window and the app (preferably in [TestCleanup])
        app.Close();
    }
    
于 2016-10-26T20:40:08.753 回答
11

@马特大卫,

请阅读文档并查看 Microsoft CompositeWPF(又名 Prism)的代码示例。这是一个专门为教授如何以测试驱动的方式处理 MVP/MVC 架构而创建的项目。他们的示例应用程序包含针对演示者\控制器的单元测试和非常酷的 UI 验收测试(他们使用White 框架来模拟用户操作)

于 2008-09-12T05:13:43.937 回答
10

手动。如果这就是你所得到的,我不是自动化UI 测试的忠实拥护者。我不确定 WPF 指南(需要通过 aku 的链接阅读).. 因为可以说它们仍在巩固...... WPF 从“什么是正确的方式”的角度来看并没有稳定下来。除非您使用这些不断发展的框架之一..我会保守地努力

  • 无情地测试(自动化的,最好是TDDed)逻辑/演示器/控制器。我不是在提倡马虎或嗜睡
  • 保持 UI 皮肤薄,并让一些讨厌的测试人员通过探索性测试对其进行(手动)破解——在 UI 方面,没有什么比“来自地狱的测试人员”更好的了。努力:自动化这种测试的收益比是巨大的,没有抓住一切,没有意义......除了安抚高层'看经理!没有手!自测用户界面!

PS:你可能想看这个(Mary Poppendieck 的 Google Talk on Lean).. 尤其是关于在测试中自动化的部分

于 2008-09-12T06:03:42.817 回答
6

由于 Coded UI 框架在 Visual Studio 版本 2019 ( Deprecated Coded UI ) 之后过期,Microsoft 建议使用带有 WinAppDriver 的 Appium 来测试 Windows 应用程序(桌面和 UWP)。您可以直接使用 Appium(带有 WinAppDriver)或 WinAppDriver 来运行测试(带有或不带有 Appium 的 WinAppDriver)。

WinAppDriver 直接

以下是直接使用 WinAppDriver 的简短描述:

  • 下载并安装 WinAppDriver:

    WinAppDriver 发布

  • 在 Windows 设置中启用开发者模式

  • 启动 WinAppDriver:

    C:\Program Files (x86)\Windows 应用程序驱动程序\WinAppDriver.exe

  • 创建一个新的 Visual Studio 2019 单元测试项目 (.NET Framework)

  • 添加 NuGet 包:Appium.WebDriver Microsoft.WinAppDriver.Appium.WebDriver(来自 Microsoft 的评论:建议使用 WinAppDriver NuGet 包来充分利用 Actions API 的高级输入。)

  • 添加一个新类 DesktopSession:

    public class DesktopSession
    {
        protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
        private const string NotepadAppId = @"C:\Windows\System32\notepad.exe";
    
        protected static WindowsDriver<WindowsElement> session;
        protected static WindowsElement editBox;
    
        public static void Setup(TestContext context)
        {
            // Launch a new instance of Notepad application
            if (session == null)
            {
                // Create a new session to launch Notepad application
                var appCapabilities = new DesiredCapabilities();
                appCapabilities.SetCapability("app", NotepadAppId);
                appCapabilities.SetCapability("platformName", "Windows");
                appCapabilities.SetCapability("deviceName ", "WindowsPC");
                session = new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), appCapabilities);
                Assert.IsNotNull(session);
                Assert.IsNotNull(session.SessionId);
    
                // Set implicit timeout to 1.5 seconds to make element search to retry every 500 ms for at most three times
                session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1.5);
    
                // Keep track of the edit box to be used throughout the session
                editBox = session.FindElementByClassName("Edit");
                Assert.IsNotNull(editBox);
            }
        }
    
        public static void TearDown()
        {
            // Close the application and delete the session
            if (session != null)
            {
                session.Close();
    
                try
                {
                    // Dismiss Save dialog if it is blocking the exit
                    session.FindElementByName("Nicht speichern").Click();
                }
                catch { }
    
                session.Quit();
                session = null;
            }
        }
    
        [TestInitialize]
        public void TestInitialize()
        {
            // Select all text and delete to clear the edit box
            editBox.SendKeys(Keys.Control + "a" + Keys.Control);
            editBox.SendKeys(Keys.Delete);
            Assert.AreEqual(string.Empty, editBox.Text);
        }
    } 
  • 更改 UnitTest1 类中的代码
        [TestClass]
        public class UnitTest1 : DesktopSession
        {
            [TestMethod]
            public void EditorEnterText()
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                editBox.SendKeys("abcdeABCDE 12345");
                Assert.AreEqual(@"abcdeABCDE 12345", editBox.Text);
            }
    
            [ClassInitialize]
            public static void ClassInitialize(TestContext context)
            {
                Setup(context);
            }
    
            [ClassCleanup]
            public static void ClassCleanup()
            {
                TearDown();
            }
        }
  • 运行你的测试

(示例代码主要复制自WinAppDriver .NotepadTest)。

Appium 与 WinAppDriver

如果你想使用 Appium 运行测试,那么你必须在你的机器上安装正确版本的 WinAppDriver。Appium 的安装程序还应该在您的机器上安装正确版本的 WinAppDriver(请为所有用户安装 Appium)。就我而言,不幸的是,这不起作用。所以我看一下文件:

C:\Program Files\Appium\resources\app\node_modules\appium\node_modules\appium-windows-driver\lib\installer.js

在这里您将找到正确的版本和下载路径:

const WAD_VER = "1.1";
const WAD_DL = `https://github.com/Microsoft/WinAppDriver/releases/download/v${WAD_VER}/WindowsApplicationDriver.msi`;

如果你安装了正确的 WinAppDriver,你就可以启动 Appium。

重要提示:您必须更改 ApplicationDriverUrl

protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723/wd/hub";

工具:

WindowsAppDriver 和 UI REcorder 发布 或下载WinAppDriver 存储库并在子目录 tools\UIRecorder 中构建 WinAppDriverUIRecorder.sln

介绍 WinAppDriver UI 记录器

  • inspect.exe:需要 Windows SDK(查看 C:\Program Files (x86)\Windows Kits\10\bin)

其他链接: WinAppDriver FAQ Appium

于 2019-07-18T06:59:01.917 回答
5

这个问题仍然是相关的,但许多答案已经过时了。@deadpikle在评论 中提出了一个很好的解决方案,我试过了,我想把它作为答案,以便更多人看到。

所以,这里有一个库https://github.com/FlaUI/FlaUI。这是 WPF 应用程序的快速入门指南:

  1. 从 nuget 安装 FlaUI.UIA3

  2. 写这个来测试应用程序是否正确运行(但插入你的字符串文字):

    using FlaUI.Core;
    using FlaUI.Core.AutomationElements;
    using FlaUI.UIA3;
    using FluentAssertions;
    using System;
    using Xunit;
    
    namespace Functional
    {
        public sealed class General : IDisposable
        {
            private readonly Application _app = Application.Launch(@"..\App.exe");
    
            [Fact]
            public void AppStarts()
            {
                using var automation = new UIA3Automation();
                Window window = _app.GetMainWindow(automation, TimeSpan.FromSeconds(3));
    
                window.Should().NotBeNull("null means the window failed to load");
    
                window.Title.Should().Be("App title",
                    "otherwise, it could be message box with error in case of the wrong configuration");
            }
    
            public void Dispose()
            {
                _app.Close();
                _app.Dispose();
            }
        }
    }
    

此代码在 GitHub Actions 管道中也能很好地工作。

于 2020-08-06T16:09:44.567 回答
0

一定要看看 TestAutomationFX.com。一个人可以投入(好吧,我做过)很多时间来尝试捕捉/记录与 White 的事件。(在我的任务开始时,我忽略了其他地方提到的一两个帖子)。

我当然第二点关于最好的测试类型不是 UI 测试。

但是,如果有人打算在 UI 中做一些可自动化的事情来解决其他类型测试覆盖的缺点,那么 TAFX 似乎是那里最快的途径。

于 2008-12-04T16:02:54.647 回答
0

尝试使用 Ranorex V2.0 实现 WPF 自动化。使用 RanoreXPath 和 Ranorex 存储库,测试自动化代码可以与识别信息完全分离。Ranorex 还提供了基于 RanoreXPath 对象的捕获/回放编辑器。

于 2008-12-09T20:49:09.167 回答
0

我会推荐 TestAutomationFX 以及简单的 ui 测试自动化。TestAutomationFX 允许您使用 wpf 的 netAdvantage 工具,它不适用于白色和 QTP。TestAutomationFX 具有易于使用的界面,它与 Visual Studio 集成,并具有用于记录用户事件的良好记录器。

于 2010-07-15T15:49:33.407 回答