DevExpress WinForm拥有180组件和UI库能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序无论是Office风格的界面还是分析处理大批量的业务数据它都能轻松胜任DevExpress新旧版本帮助文档下载欢迎进QQ qun获取169725316UI自动化测试利用特定的工具/框架来模拟用户与界面的交互并帮助确保应用程序满足相关的最终用户需求。当与其他测试方法(API测试、单元测试等)结合使用时UI自动化可以提高应用程序的稳定性减少花在手工测试上的时间当然还可以提高用户满意度。在本文中我们将向您展示如何使用UI自动化在Visual Studio 2022中编写简单/高级UI测试。在开始之前我们先看看UI测试的优势UI测试以应用程序为目标允许您测试应用程序流(端到端测试)涵盖应用程序的所有元素包括UI和业务逻辑(而单元测试侧重于测试应用程序中的单个模块、类或组件)。UI测试有助于识别与导航、数据输入和跨不同屏幕的工作流相关的问题这些问题可能不会被其他测试捕获。UI测试为测试复杂场景和边缘情况提供了效率和可伸缩性(单元测试对于测试单个代码单元是必不可少的)。请注意UI测试可能需要更长的时间来执行因为它们与UI交互并在应用程序开发管道中稍后运行(单元测试通常更快并且在提交到存储库之前进行了检查)。在上文中我们为大家介绍了UI测试自动化是如何工作的、开始创建UI自动化测试等本文将继续介绍如何创还能UI自动化测试。创建UI自动化测试3. 为登录表单创建测试在进行测试之前我想澄清几点AutomationElement.RootElement静态属性包含根元素使用此属性访问应用程序。AutomationElement.FindFirst方法允许您找到一个特定的UI元素AutomationElement logInFormElement AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, CRM Log In Form));FindFirst方法有两个参数第一个参数(scope)指定搜索的范围第二个参数(条件)指定要匹配的标准(在我的例子中这是一个AutomationName CRM Log In Form的表单)。UI控件可以根据其他设置(例如Text)自动“计算”AutomationName。如果需要您可以显式地设置AutomationName属性或处理DXAccessible.QueryAccessibleInfo事件来向​​​​​​​DevExpress UI元素提供可访问性信息。在某些情况下被测试的应用程序可能没有时间生成UI元素因为UI自动化框架执行操作非常快。因此我们建议使用“poll”间隔。下面的例子实现了FindFirstWithTimeout方法并反复调用FindFirst(带有延迟)直到找到指定的UI元素public static class AutomationElementExtensions { public static AutomationElement FindFirstWithTimeout(this AutomationElement this, TreeScope scope, Condition condition, int timeoutMilliseconds 1000) { Stopwatch stopwatch new Stopwatch(); stopwatch.Start(); do { var result this.FindFirst(scope, condition); if (result ! null) return result; Thread.Sleep(100); } while (stopwatch.ElapsedMilliseconds timeoutMilliseconds); return null; } }下面的测试将执行以下操作输入错误的登录名和密码。确保在“LogIn”表单中显示错误消息。[Test] public void NonExistingUsernameLoginTest() { afterLogInAction CheckErrorLabel; LogIn(TestNonExistingUser, 123456); } void CheckErrorLabel() { AutomationElement errorLabelElement loginForm.FindFirstByNameWithTimeout( TreeScope.Children, Invalid User or Password, 10000); Assert.IsNotNull(errorLabelElement); } void LogIn(string username, string password) { // Finds the LogIn form and its main UI elements. loginForm AutomationElement.RootElement.FindFirstByNameWithTimeout( TreeScope.Children, logInFormAccessbleName, 10000); AutomationElement usernameElement loginForm.FindFirstByNameWithTimeout(TreeScope.Children, usernameAccessbleName, 10000); AutomationElement passwordElement loginForm.FindFirstByNameWithTimeout(TreeScope.Children, passwordAccessbleName, 10000); AutomationElement logInButtonElement loginForm.FindFirstByNameWithTimeout(TreeScope.Children, logInButtonAccessbleName, 10000); // Gets automation patterns to fill UserName and Password inputs (editors). ValuePattern usernameValuePattern (ValuePattern)usernameElement.GetCurrentPattern(ValuePattern.Pattern); ValuePattern passwordValuePattern (ValuePattern)passwordElement.GetCurrentPattern(ValuePattern.Pattern); InvokePattern invokePattern (InvokePattern)logInButtonElement.GetCurrentPattern(InvokePattern.Pattern); // Sets editor values. Fills in username and password input fields. usernameValuePattern.SetValue(username); passwordValuePattern.SetValue(password); invokePattern.Invoke(); // Performs an action after a log in attempt. afterLogInAction?.Invoke(); }正如您所看到的编写测试可以归结为获取一个AutomationElement并调用它的模式方法。4. 为客户表单创建一个测试让我们考虑一个更复杂的情况并在​​​​​​​DevExpress WinForms数据网格(GridControl)中测试数据编辑。DevExpress数据网格包含一个带有布尔值的“Is Modified”未绑定列该列的值表示用户是否修改了“Name”列的值。我使用TablePattern与网格控件一起工作下面的例子展示了如何编写一个测试来修改我们的WinForms Grid中的客户名称并检查“Is Modified”列中的值是否从false变为true[Test] public void ModifiedCustomerTest() { LogIn(testExistingUserLogin, testExistingUserPassword); // Finds the GridControl and gets its TablePattern. customersForm AutomationElement.RootElement.FindFirstByNameWithTimeout( TreeScope.Children, customersFormAccessbleName, 10000); AutomationElement customersGrid customersForm.FindFirstByIdWithTimeout( TreeScope.Children, customersGridAutomationID, 10000); TablePattern customersTablePattern (TablePattern)customersGrid.GetCurrentPattern(TablePattern.Pattern); // Activates a cell within the GridControl. AutomationElement cellToUpdate customersTablePattern.GetItem(1, 1); InvokePattern testCellInvokePattern (InvokePattern)cellToUpdate.GetCurrentPattern(InvokePattern.Pattern); testCellInvokePattern.Invoke(); // Modifies the cells value. AutomationElement editingControl customersGrid.FindFirstByNameWithTimeout(TreeScope.Descendants, Editing control, 1000); ValuePattern editedCellValuePattern (ValuePattern)editingControl.GetCurrentPattern(ValuePattern.Pattern); editedCellValuePattern.SetValue(Value updated!); Thread.Sleep(1000); // Sets a delay for demonstration purposes. // Selects the next data row. AutomationElement nextRowCell customersTablePattern.GetItem(2, 1); SelectionItemPattern selectionItemPattern (SelectionItemPattern)TreeWalker.ControlViewWalker.GetParent(nextRowCell).GetCurrentPattern(SelectionItemPattern.Pattern); selectionItemPattern.Select(); Thread.Sleep(1000); // Checks if the value in the Is Modified column has changed. int isModiedColumnIndex customersTablePattern.Current.GetColumnHeaders().ToList().FindIndex(h h.Current.Name Is Modified); AutomationElement isModifiedCell customersTablePattern.GetItem(1, isModiedColumnIndex); ValuePattern isModifiedCellValuePattern (ValuePattern)isModifiedCell.GetCurrentPattern(ValuePattern.Pattern); Assert.AreEqual(isModifiedCellValuePattern.Current.Value, Checked); }5. 运行测试要运行我刚刚创建的测试将用tests展开项目(“TestRunner”)右键单击*.cs文件来调用上下文菜单然后单击Run Tests。