How to test a WPF user interface?

前端 未结 9 434
余生分开走
余生分开走 2020-12-04 07:46

Using win forms with an MVC/MVP architecture, I would normally use a class to wrap a view to test the UI while using mocks for the model and controller/presenter. The wrapp

相关标签:
9条回答
  • 2020-12-04 08:24

    Because the Coded UI framework expires after Visual Studio version 2019 (Deprecated Coded UI), Microsoft recommends Appium with WinAppDriver for testing Windows applications (Desktop and UWP). You can use Appium (with WinAppDriver) or WinAppDriver directly to run the tests (WinAppDriver with or without Appium).

    WinAppDriver directly

    Here is a short description to work with the WinAppDriver directly:

    • download and install WinAppDriver:

      WinAppDriver Release

    • enable Developer Mode in Windows settings

    • start the WinAppDriver:

      C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe

    • create a new Visual Studio 2019 Unit Test Project (.NET Framework)

    • add the NuGet-Package: Appium.WebDriver Microsoft.WinAppDriver.Appium.WebDriver (comment from Microsoft: it is recommenced to use the WinAppDriver NuGet package to take full advantage of the advanced input with the Actions API.)

    • add a new class 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);
            }
        } 
    
    • Change the code from the UnitTest1 class
            [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();
                }
            }
    
    • run your test

    (the sample code is mainly copied from WinAppDriver .NotepadTest).

    Appium with WinAppDriver

    If you want to run your tests using Appium, then you must have installed the correct version of the WinAppDriver on your machine. The installer of Appium should also install the WinAppDriver with the correct version on your machine (please install Appium for all users). In my case, unfortunately, this did not work. So I take a look in the file:

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

    Here you will find the correct version and the download path:

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

    If you have installed the correct WinAppDriver you can start Appium.

    Important: you have to change the ApplicationDriverUrl

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

    Tools:

    • WindowsAppDriver UI Recorder

    WindowsAppDriver and UI REcorder releases or Donwload the WinAppDriver repository and build the WinAppDriverUIRecorder.sln in the subdirectory tools\UIRecorder

    Introducing WinAppDriver UI Recorder

    • inspect.exe: Windows SDK is required (look in C:\Program Files (x86)\Windows Kits\10\bin)

    Other links: WinAppDriver FAQ Appium

    0 讨论(0)
  • 2020-12-04 08:28

    Try Ranorex V2.0 for WPF automation. With RanoreXPath and Ranorex repository test automation code could be completely seperated from identification information. Ranorex also provides a capture/replay editor based on RanoreXPath objects.

    0 讨论(0)
  • 2020-12-04 08:30

    The question is still relevant, but many of the answers got obsolete. @deadpikle suggested a very good solution in the comment, I tried it and I want to make it as an answer in order to more people see it.

    So, here is a library https://github.com/FlaUI/FlaUI. Here is a quick start guide for WPF app:

    1. Install FlaUI.UIA3 from nuget

    2. Write this to test if app runs correctly (but insert your string literals):

      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();
              }
          }
      }
      

    This code also works well in the GitHub Actions pipeline.

    0 讨论(0)
  • 2020-12-04 08:31

    Manually. I'm not a big fan of automated UI testing if that is what you're getting at. I'm not sure about the WPF guidances (need to read thru aku's links).. because they are still solidifying so to speak... WPF has not stabilized from the point of 'what is the right way'. Unless you're using one of these evolving frameworks.. I'd be conservative w.r.t. effort

    • Test (Automated preferably TDDed) the logic/presenters/controllers ruthlessly. I'm not advocating sloppiness or lethargy.
    • Keep the UI skin thin and get some nasty testers to go have a (manual) crack at it with exploratory testing - nothing is as good as a 'tester from Hell' when it comes to UIs. The effort : gain ratio from automating this kind of testing is huge, doesn't catch everything and doesn't make sense... except to pacify the higher ups 'Look Mgr! No hands! self-testing UIs!'

    PS: you may want to watch this (Mary Poppendieck's Google Talk on Lean).. especially the part about what to automate in testing

    0 讨论(0)
  • 2020-12-04 08:33

    Definitely look at TestAutomationFX.com. One can invest (OK, I did) a lot of time trying to capture / record events with White. (At the start of my quest I ignored the post or two in other places referring to it).

    I of course second the other points about the best type of testing not being UI testing.

    But if someone is going to do something automatable in the UI to get around shortcomings in other types of testing coverage, TAFX seems the quickest route there.

    0 讨论(0)
  • 2020-12-04 08:33

    I would recommend TestAutomationFX as well for simple automation of ui testing. TestAutomationFX lets you work with netAdvantage tools for wpf aswell , which doesnt work with white and QTP. TestAutomationFX has a easy to use interface , it integrates with visual studio and has a good recorder for recording user events.

    0 讨论(0)
提交回复
热议问题