<p>Using win forms with an <a href="http://en.wikipedia.org/wiki/Model-view-controller" rel="noreferrer">MVC</a>/<a href="http://msdn.microsoft.com/en-us/magazine/cc188690.aspx" rel="noreferrer">MVP</a> 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 wrapper class would make most everything in the UI an observable property for the test runner through properties and events.</p>

<p>Would this be a viable approach to testing a WPF app?  Is there a better way? Are there any gotchas to watch out for?</p>

[{'answer_id': 58349, 'author': 'aku', 'author_id': 1196, 'author_profile': 'https://Stackoverflow.com/users/1196', 'pm_score': 4, 'selected': False, 'text': '<p>@Matt David,</p>\n\n<p>Please read documentation and take a look at the code samples for Microsoft <a href="http://www.codeplex.com/CompositeWPF" rel="noreferrer">CompositeWPF</a> (aka Prism). It\'s a project created specifically to teach how to deal with MVP/MVC architecture in test-driven manner. Their sample application contains unit tests for presenters\\controllers and very cool acceptance tests for UI (they use <a href="http://www.codeplex.com/white" rel="noreferrer">White framework</a> to simulate user actions)</p>\n'}, {'answer_id': 58390, 'author': 'Gishu', 'author_id': 1695, 'author_profile': 'https://Stackoverflow.com/users/1695', 'pm_score': 3, 'selected': False, 'text': '<p><strong>Manually.</strong> I\'m not a big fan of automated <em>UI testing</em> 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</p>\n\n<ul>\n<li>Test (Automated preferably TDDed) the logic/presenters/controllers ruthlessly. <em>I\'m not advocating sloppiness or lethargy</em>.  </li>\n<li><strong>Keep the UI skin thin and get some nasty testers</strong> 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!\'</li>\n</ul>\n\n<p>PS: you may want to watch <a href="http://video.google.com/videoplay?docid=-5105910452864283694" rel="noreferrer">this (Mary Poppendieck\'s Google Talk on Lean).. especially the part about what to automate in testing</a></p>\n'}, {'answer_id': 120076, 'author': 'Kjetil Klaussen', 'author_id': 15599, 'author_profile': 'https://Stackoverflow.com/users/15599', 'pm_score': 7, 'selected': True, 'text': '<p>As for the testing itself, you\'re probably best off using the <a href="https://msdn.microsoft.com/library/ms747327.aspx" rel="noreferrer">UI Automation</a> framework. Or if you want a more fluent and wpf/winforms/win32/swt-independent way of using the framework, you could download <a href="http://www.codeplex.com/white" rel="noreferrer">White</a> from Codeplex (provided that you\'re in a position to use open source code in your environment).</p>\n\n<p>For the gotchas; If you\'re trying to test your views, you will probably run in to some threading issues. For instance, if you\'re running NUnit the default testrunner will run in MTA (Multi-Threaded Appartment), while as WPF needs to run as STA (Single-threaded Appartment). <a href="http://miketwo.blogspot.com/2007/03/unit-testing-wpf-controls-with.html" rel="noreferrer">Mike Two</a> has a real easy getting-started on unit testing WPF, but without considering the threading issue. Josh Smith has some thoughts on the threading issue in <a href="http://joshsmithonwpf.wordpress.com/2007/07/09/using-nunit-with-wpf/" rel="noreferrer">this post</a>, and he also points to <a href="http://www.hedgate.net/articles/2007/01/08/instantiating-a-wpf-control-from-an-nunit-test/" rel="noreferrer">this article</a> by Chris Hedgate. Chris uses a modified version of Peter Provost\'s <a href="http://www.peterprovost.org/blog/post/NUnit-and-Multithreaded-Tests-CrossThreadTestRunner.aspx" rel="noreferrer">CrossThreadTestRunner</a> to wrap the MTA/STA issues in a bit more friendly way. </p>\n'}, {'answer_id': 341120, 'author': 'Ruben Bartelink', 'author_id': 11635, 'author_profile': 'https://Stackoverflow.com/users/11635', 'pm_score': 0, 'selected': False, 'text': '<p>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).</p>\n\n<p>I of course second the other points about the best type of testing not being UI testing.</p>\n\n<p>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.</p>\n'}, {'answer_id': 354190, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 0, 'selected': False, 'text': '<p>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.</p>\n'}, {'answer_id': 3257325, 'author': 'Gokul', 'author_id': 385941, 'author_profile': 'https://Stackoverflow.com/users/385941', 'pm_score': 0, 'selected': False, 'text': '<p>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.</p>\n'}, {'answer_id': 40271736, 'author': 'Justas', 'author_id': 407108, 'author_profile': 'https://Stackoverflow.com/users/407108', 'pm_score': 4, 'selected': False, 'text': '<p>2016 Update: <strong>Use the free TestStack.White framework to automate WPF UI testing</strong></p>\n\n<ul>\n<li><a href="http://white.codeplex.com/" rel="noreferrer">Project White has been abandoned</a>, but its successor <a href="http://teststackwhite.readthedocs.io/en/latest/GettingStarted/" rel="noreferrer">TestStack.White</a> is available via a NuGet package.</li>\n<li>TestStack.White has utility methods for <a href="http://teststackwhite.readthedocs.io/en/latest/#getting-hold-of-a-window" rel="noreferrer">starting WPF apps</a>, <a href="http://teststackwhite.readthedocs.io/en/latest/#finding-a-ui-item-and-performing-action" rel="noreferrer">finding</a> window/<a href="http://teststackwhite.readthedocs.io/en/latest/UIItems/#wpf-items" rel="noreferrer">user control elements</a>, <a href="http://teststackwhite.readthedocs.io/en/latest/GettingStarted/#finding-a-ui-item-and-performing-action" rel="noreferrer">clicking buttons/elements</a>, simulating <a href="http://teststackwhite.readthedocs.io/en/latest/AdvancedTopics/MouseAndKeyboard/" rel="noreferrer">mouse and keyboard</a> events, <a href="http://teststackwhite.readthedocs.io/en/latest/AdvancedTopics/Waiting/" rel="noreferrer">waiting</a>, etc..</li>\n<li><p>An example that will launch a WPF app, click a button, and check for result looks like the following:</p>\n\n<pre><code>using TestStack.White;\nusing TestStack.White.UIItems;\nusing TestStack.White.Factory;\n\n[TestMethod]\npublic void TestDoSomething()\n{\n    //Opens the app\n    var app = Application.Launch("MyApp.exe");\n\n    //Finds the main window (this and above line should be in [TestInitialize])\n    var window = app.GetWindow("My App Window Title", InitializeOption.NoCache);\n\n    //Finds the button (see other Get...() methods for options)\n    var btnMyButton = window.Get&lt;Button&gt;("btnMyButtonWPFname");\n\n    //Simulate clicking\n    btnMyButton.Click();\n\n    //Gets the result text box \n    //Note: TextBox/Button is in TestStack.White.UIItems namespace\n    var txtMyTextBox = window.Get&lt;TextBox&gt;("txtMyTextBox");\n\n    //Check for the result\n    Assert.IsTrue(txtMyTextBox.Text == "my expected result");\n\n    //Close the main window and the app (preferably in [TestCleanup])\n    app.Close();\n}\n</code></pre></li>\n</ul>\n'}, {'answer_id': 57088744, 'author': 'HHenn', 'author_id': 2003805, 'author_profile': 'https://Stackoverflow.com/users/2003805', 'pm_score': 3, 'selected': False, 'text': '<p>Because the Coded UI framework expires after Visual Studio version 2019 (<a href="https://learn.microsoft.com/de-de/visualstudio/test/use-ui-automation-to-test-your-code?view=vs-2019" rel="nofollow noreferrer">Deprecated Coded UI</a>), 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 (<a href="https://github.com/Microsoft/WinAppDriver/wiki/WinAppDriver-and-Appium" rel="nofollow noreferrer">WinAppDriver with or without Appium</a>).</p>\n<p><strong>WinAppDriver directly</strong></p>\n<p>Here is a short description to work with the WinAppDriver directly:</p>\n<ul>\n<li><p>download and install WinAppDriver:</p>\n<p><a href="https://github.com/microsoft/WinAppDriver/releases" rel="nofollow noreferrer">WinAppDriver Release</a></p>\n</li>\n<li><p>enable Developer Mode in Windows settings</p>\n</li>\n<li><p>start the WinAppDriver:</p>\n<p>C:\\Program Files (x86)\\Windows Application Driver\\WinAppDriver.exe</p>\n</li>\n<li><p>create a new Visual Studio 2019 Unit Test Project (.NET Framework)</p>\n</li>\n<li><p>add the NuGet-Package: <s>Appium.WebDriver</s> 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.)</p>\n</li>\n<li><p>add a new class DesktopSession:</p>\n</li>\n</ul>\n<pre><code>    public class DesktopSession\n    {\n        protected const string WindowsApplicationDriverUrl = &quot;http://127.0.0.1:4723&quot;;\n        private const string NotepadAppId = @&quot;C:\\Windows\\System32\\notepad.exe&quot;;\n    \n        protected static WindowsDriver&lt;WindowsElement&gt; session;\n        protected static WindowsElement editBox;\n    \n        public static void Setup(TestContext context)\n        {\n            // Launch a new instance of Notepad application\n            if (session == null)\n            {\n                // Create a new session to launch Notepad application\n                var appCapabilities = new DesiredCapabilities();\n                appCapabilities.SetCapability(&quot;app&quot;, NotepadAppId);\n                appCapabilities.SetCapability(&quot;platformName&quot;, &quot;Windows&quot;);\n                appCapabilities.SetCapability(&quot;deviceName &quot;, &quot;WindowsPC&quot;);\n                session = new WindowsDriver&lt;WindowsElement&gt;(new Uri(WindowsApplicationDriverUrl), appCapabilities);\n                Assert.IsNotNull(session);\n                Assert.IsNotNull(session.SessionId);\n    \n                // Set implicit timeout to 1.5 seconds to make element search to retry every 500 ms for at most three times\n                session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1.5);\n    \n                // Keep track of the edit box to be used throughout the session\n                editBox = session.FindElementByClassName(&quot;Edit&quot;);\n                Assert.IsNotNull(editBox);\n            }\n        }\n    \n        public static void TearDown()\n        {\n            // Close the application and delete the session\n            if (session != null)\n            {\n                session.Close();\n    \n                try\n                {\n                    // Dismiss Save dialog if it is blocking the exit\n                    session.FindElementByName(&quot;Nicht speichern&quot;).Click();\n                }\n                catch { }\n    \n                session.Quit();\n                session = null;\n            }\n        }\n    \n        [TestInitialize]\n        public void TestInitialize()\n        {\n            // Select all text and delete to clear the edit box\n            editBox.SendKeys(Keys.Control + &quot;a&quot; + Keys.Control);\n            editBox.SendKeys(Keys.Delete);\n            Assert.AreEqual(string.Empty, editBox.Text);\n        }\n    } \n</code></pre>\n<ul>\n<li>Change the code from the UnitTest1 class</li>\n</ul>\n<pre><code>        [TestClass]\n        public class UnitTest1 : DesktopSession\n        {\n            [TestMethod]\n            public void EditorEnterText()\n            {\n                Thread.Sleep(TimeSpan.FromSeconds(2));\n                editBox.SendKeys(&quot;abcdeABCDE 12345&quot;);\n                Assert.AreEqual(@&quot;abcdeABCDE 12345&quot;, editBox.Text);\n            }\n    \n            [ClassInitialize]\n            public static void ClassInitialize(TestContext context)\n            {\n                Setup(context);\n            }\n    \n            [ClassCleanup]\n            public static void ClassCleanup()\n            {\n                TearDown();\n            }\n        }\n</code></pre>\n<ul>\n<li>run your test</li>\n</ul>\n<p>(the sample code is mainly copied from <a href="https://github.com/microsoft/WinAppDriver/tree/master/Samples/C%23/NotepadTest" rel="nofollow noreferrer">WinAppDriver\n.NotepadTest</a>).</p>\n<p><strong>Appium with WinAppDriver</strong></p>\n<p>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).\nIn my case, unfortunately, this did not work. So I take a look in the file:</p>\n<pre><code>C:\\Program Files\\Appium\\resources\\app\\node_modules\\appium\\node_modules\\appium-windows-driver\\lib\\installer.js\n</code></pre>\n<p>Here you will find the correct version and the download path:</p>\n<pre><code>const WAD_VER = &quot;1.1&quot;;\nconst WAD_DL = `https://github.com/Microsoft/WinAppDriver/releases/download/v${WAD_VER}/WindowsApplicationDriver.msi`;\n</code></pre>\n<p>If you have installed the correct WinAppDriver you can start Appium.</p>\n<p><em>Important</em>: you have to change the ApplicationDriverUrl</p>\n<pre><code>protected const string WindowsApplicationDriverUrl = &quot;http://127.0.0.1:4723/wd/hub&quot;;\n</code></pre>\n<p>Tools:</p>\n<ul>\n<li><a href="https://github.com/microsoft/WinAppDriver/tree/master/Tools/UIRecorder" rel="nofollow noreferrer">WindowsAppDriver UI Recorder</a></li>\n</ul>\n<p><a href="https://github.com/microsoft/WinAppDriver/releases" rel="nofollow noreferrer">WindowsAppDriver and UI REcorder releases</a>\nor\nDonwload the <a href="https://github.com/microsoft/WinAppDriver/releases" rel="nofollow noreferrer">WinAppDriver repository</a> and build the WinAppDriverUIRecorder.sln in the subdirectory tools\\UIRecorder</p>\n<p><a href="https://blogs.windows.com/windowsdeveloper/2018/06/20/introducing-winappdriver-ui-recorder/#jR4rmH2V4zpbYIe0.97" rel="nofollow noreferrer">Introducing WinAppDriver UI Recorder</a></p>\n<ul>\n<li>inspect.exe: Windows SDK is required (look in C:\\Program Files (x86)\\Windows Kits\\10\\bin)</li>\n</ul>\n<p>Other links:\n<a href="https://github.com/Microsoft/WinAppDriver/wiki/Frequently-Asked-Questions/289a8b325d3ddab9f08b4398c49163a9a136f607#running-on-a-remote-machine" rel="nofollow noreferrer">WinAppDriver FAQ</a>\n<a href="http://appium.io/" rel="nofollow noreferrer">Appium</a></p>\n'}, {'answer_id': 63287686, 'author': 'Lev', 'author_id': 3087417, 'author_profile': 'https://Stackoverflow.com/users/3087417', 'pm_score': 3, 'selected': False, 'text': '<p>The question is still relevant, but many of the answers got obsolete. <a href="https://stackoverflow.com/questions/58340/how-to-test-a-wpf-user-interface#comment105831827_40271736">@deadpikle</a>\nsuggested a very good solution in the <a href="https://stackoverflow.com/questions/58340/how-to-test-a-wpf-user-interface#comment105831827_40271736">comment</a>, I tried it and I want to make it as an answer in order to more people see it.</p>\n<p>So, here is a library <a href="https://github.com/FlaUI/FlaUI" rel="noreferrer">https://github.com/FlaUI/FlaUI</a>. Here is a quick start guide for WPF app:</p>\n<ol>\n<li><p>Install FlaUI.UIA3 from nuget</p>\n</li>\n<li><p>Write this to test if app runs correctly (but insert your string literals):</p>\n<pre><code>using FlaUI.Core;\nusing FlaUI.Core.AutomationElements;\nusing FlaUI.UIA3;\nusing FluentAssertions;\nusing System;\nusing Xunit;\n\nnamespace Functional\n{\n    public sealed class General : IDisposable\n    {\n        private readonly Application _app = Application.Launch(@&quot;..\\App.exe&quot;);\n\n        [Fact]\n        public void AppStarts()\n        {\n            using var automation = new UIA3Automation();\n            Window window = _app.GetMainWindow(automation, TimeSpan.FromSeconds(3));\n\n            window.Should().NotBeNull(&quot;null means the window failed to load&quot;);\n\n            window.Title.Should().Be(&quot;App title&quot;,\n                &quot;otherwise, it could be message box with error in case of the wrong configuration&quot;);\n        }\n\n        public void Dispose()\n        {\n            _app.Close();\n            _app.Dispose();\n        }\n    }\n}\n</code></pre>\n</li>\n</ol>\n<p>This code also works well in the GitHub Actions pipeline.</p>\n'}]
['https://Stackoverflow.com/questions/58340', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/3826/']