一、「创建 Test 项目」章节:环境与前置配置(新手必看)
1. 被测 WPF 项目的前置配置(必须做!)
要让 FlaUI 能定位到 WPF 控件,需给 WPF 界面的控件设置AutomationId(唯一标识,比控件 Name 更稳定):打开 WPF 项目的MainWindow.xaml,给登录相关控件添加AutomationProperties.AutomationId:
XML
<!-- WPF登录界面的XAML示例 -->
<Grid>
<!-- 账号输入框 -->
<TextBox x:Name="txtAccount"
AutomationProperties.AutomationId="Login_AccountInput"
Width="200" Height="30" Margin="10"/>
<!-- 密码输入框 -->
<PasswordBox x:Name="txtPwd"
AutomationProperties.AutomationId="Login_PwdInput"
Width="200" Height="30" Margin="10,50,10,0"/>
<!-- 登录按钮 -->
<Button x:Name="btnLogin"
AutomationProperties.AutomationId="Login_LoginBtn"
Content="登录" Width="80" Height="30" Margin="10,90,10,0"
Click="BtnLogin_Click"/>
<!-- 主页面标题(登录成功后显示) -->
<TextBlock x:Name="txtHomeTitle"
AutomationProperties.AutomationId="HomePage_Title"
Text="主页面" Visibility="Collapsed" Margin="10,130,10,0"/>
</Grid>
2. 测试项目的 NuGet 包安装步骤
打开 Visual Studio → 右键测试项目 → 选择「管理 NuGet 程序包」:
- 搜索
NUnit→ 安装 3.13.3+版本(稳定版) - 搜索
NUnit3TestAdapter→ 安装(用于在 VS 中运行 NUnit 测试) - 搜索
FlaUI.Core→ 安装最新稳定版(如 4.0.0+) - 搜索
FlaUI.UIA3→ 安装(WPF 应用优先用 UIA3 框架,兼容性更强)
3. 配置nunit.runsettings文件(统一测试环境)
- 在测试项目根目录右键 → 「添加」→「新建项」→ 选「XML 文件」,命名为
nunit.runsettings - 粘贴以下配置(指定测试报告路径、框架版本):
XML
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<!-- 被测程序路径(可根据实际修改) -->
<TestRunParameters>
<Parameter name="TestAppPath" value="..\..\..\YourWpfApp\bin\Debug\net6.0-windows\YourWpfApp.exe" />
</TestRunParameters>
<!-- NUnit配置 -->
<NUnit>
<NumberOfTestWorkers>1</NumberOfTestWorkers> <!-- UI自动化建议单线程 -->
<OutputXml>TestResults\NUnit_Report.xml</OutputXml> <!-- 原生XML报告路径 -->
</NUnit>
<!-- .NET框架配置 -->
<RunnerConfiguration>
<TargetFrameworkVersion>net6.0</TargetFrameworkVersion> <!-- 与被测项目一致 -->
</RunnerConfiguration>
</RunSettings>
- 应用配置:VS 顶部「测试」→「测试设置」→「选择测试设置文件」→ 选中刚创建的
nunit.runsettings
二、「用户登录」章节:完整测试代码 + 细节处理
1. 测试类的基础结构(含初始化 / 清理)
cs
using NUnit.Framework;
using FlaUI.Core;
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;
using System;
using System.IO;
namespace WpfUiAutoTest
{
// NUnit测试类
[TestFixture]
public class LoginTests
{
// 核心对象:自动化框架、被测应用、主窗口
private UIA3Automation _automation;
private Application _app;
private Window _mainWindow;
// 被测程序路径(从runsettings中读取)
private string _testAppPath;
// 【全局初始化】所有测试前执行1次
[OneTimeSetUp]
public void GlobalSetup()
{
// 从runsettings读取被测程序路径
_testAppPath = TestContext.Parameters["TestAppPath"];
// 验证路径是否存在
if (!File.Exists(_testAppPath))
{
throw new FileNotFoundException("被测WPF程序不存在,请检查路径", _testAppPath);
}
// 初始化FlaUI自动化框架
_automation = new UIA3Automation();
}
// 【每个测试前初始化】每个测试用例执行前启动应用
[SetUp]
public void TestSetup()
{
// 启动被测WPF程序
_app = Application.Launch(_testAppPath);
// 等待应用启动(最多等10秒)
_app.WaitUntilMainWindowIsLoaded(TimeSpan.FromSeconds(10));
// 获取主窗口
_mainWindow = _app.GetMainWindow(_automation);
// 最大化窗口(避免元素位置偏移)
_mainWindow.Maximize();
}
// 【用户登录测试用例】
[Test]
[Description("验证正确账号密码能否成功登录")]
public void Login_WithValidAccount_Success()
{
// --------------------------
// 步骤1:定位登录界面元素
// --------------------------
// 账号输入框(等待元素加载,最多5秒)
var accountInput = _mainWindow
.WaitUntilExists(cf => cf.ByAutomationId("Login_AccountInput"), TimeSpan.FromSeconds(5))
?.AsTextBox();
Assert.IsNotNull(accountInput, "账号输入框未找到");
// 密码输入框
var pwdInput = _mainWindow
.WaitUntilExists(cf => cf.ByAutomationId("Login_PwdInput"), TimeSpan.FromSeconds(5))
?.AsPasswordBox(); // 注意:PasswordBox需用AsPasswordBox()
Assert.IsNotNull(pwdInput, "密码输入框未找到");
// 登录按钮(等待按钮可点击)
var loginBtn = _mainWindow
.WaitUntilExists(cf => cf.ByAutomationId("Login_LoginBtn"), TimeSpan.FromSeconds(5))
?.AsButton();
Assert.IsNotNull(loginBtn, "登录按钮未找到");
Assert.IsTrue(loginBtn.IsEnabled, "登录按钮不可点击");
// --------------------------
// 步骤2:模拟用户操作
// --------------------------
// 输入账号(清空原有内容)
accountInput.Text = string.Empty;
accountInput.Enter("test_user");
// 输入密码(PasswordBox需用SecurePassword,或直接Enter)
pwdInput.Password = string.Empty;
pwdInput.Enter("test_pwd_123");
// 点击登录按钮
loginBtn.Click();
// --------------------------
// 步骤3:验证登录结果
// --------------------------
// 等待主页面标题显示(最多等5秒)
var homeTitle = _mainWindow
.WaitUntilExists(cf => cf.ByAutomationId("HomePage_Title"), TimeSpan.FromSeconds(5))
?.AsTextBlock();
Assert.IsNotNull(homeTitle, "登录后未进入主页面");
Assert.AreEqual("主页面", homeTitle.Text, "主页面标题显示错误");
}
// 【每个测试后清理】关闭应用,释放资源
[TearDown]
public void TestTearDown()
{
// 关闭应用(优先优雅关闭,失败则强制终止)
if (_app != null)
{
try
{
_app.Close();
// 等待进程退出(最多5秒)
if (!_app.WaitForExit(TimeSpan.FromSeconds(5)))
{
_app.Kill();
}
}
catch (Exception ex)
{
TestContext.WriteLine($"关闭应用失败:{ex.Message}");
_app?.Kill();
}
}
// 释放对象
_mainWindow?.Dispose();
_app?.Dispose();
}
// 【全局清理】所有测试后释放框架
[OneTimeTearDown]
public void GlobalTearDown()
{
_automation?.Dispose();
}
}
}
2. 常见问题处理(新手易踩坑)
- 密码框输入失败 :WPF 的
PasswordBox不能用AsTextBox(),必须用AsPasswordBox(),且优先用Enter()方法输入(模拟真实键盘输入)。 - 元素定位不稳定 :避免用
By.Name()定位(Name 可能随语言切换变化),优先用ByAutomationId();如果控件没有AutomationId,可结合By.ControlType()+By.Index()(但稳定性较差)。 - 应用启动超时 :如果 WPF 程序启动慢,可延长
WaitUntilMainWindowIsLoaded的超时时间(如 15 秒)。
三、「导出测试文件」章节:ExtentReports 可视化报告(带截图)
1. 安装 ExtentReports 包
在测试项目的 NuGet 中搜索ExtentReports,安装 4.1.0+版本(兼容 NUnit3)。
2. 集成 ExtentReports 到测试类
cs
// 新增引用
using AventStack.ExtentReports;
using AventStack.ExtentReports.Reporter;
using FlaUI.Core.Capturing;
// 在LoginTests类中新增以下成员
private static ExtentReports _extentReport;
private ExtentTest _currentTest;
// 【全局初始化】添加报告初始化
[OneTimeSetUp]
public void GlobalSetup()
{
// 原有逻辑...
// 初始化ExtentReports
var reportDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestResults");
Directory.CreateDirectory(reportDir); // 确保目录存在
var htmlReporter = new ExtentHtmlReporter(Path.Combine(reportDir, "Extent_Report.html"));
// 配置报告样式(可选)
htmlReporter.Config.DocumentTitle = "WPF UI自动化测试报告";
htmlReporter.Config.ReportName = "用户登录模块测试";
htmlReporter.Config.Theme = Theme.Dark; // 深色主题
_extentReport = new ExtentReports();
_extentReport.AttachReporter(htmlReporter);
}
// 【每个测试前】创建测试报告节点
[SetUp]
public void TestSetup()
{
// 原有逻辑...
// 创建当前测试的报告节点
_currentTest = _extentReport.CreateTest(TestContext.CurrentContext.Test.Name,
TestContext.CurrentContext.Test.Properties.Get("Description")?.ToString());
}
// 【用户登录测试用例】新增报告日志+截图
[Test]
[Description("验证正确账号密码能否成功登录")]
public void Login_WithValidAccount_Success()
{
try
{
_currentTest.Log(Status.Info, "开始执行【正确账号登录】测试用例");
// 步骤1:定位元素(新增日志)
_currentTest.Log(Status.Info, "定位账号输入框");
var accountInput = _mainWindow.WaitUntilExists(cf => cf.ByAutomationId("Login_AccountInput"), TimeSpan.FromSeconds(5))?.AsTextBox();
Assert.IsNotNull(accountInput, "账号输入框未找到");
_currentTest.Log(Status.Pass, "账号输入框定位成功");
// 步骤2:模拟输入(新增日志)
_currentTest.Log(Status.Info, "输入账号:test_user");
accountInput.Text = string.Empty;
accountInput.Enter("test_user");
// 步骤3:点击登录后,添加界面截图
loginBtn.Click();
_currentTest.Log(Status.Info, "点击登录按钮");
// 捕获当前界面截图
var screenshot = Capture.Screenshot(_mainWindow);
var screenshotPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestResults", $"{TestContext.CurrentContext.Test.Name}_after_login.png");
screenshot.Save(screenshotPath);
// 将截图添加到报告
_currentTest.AddScreenCaptureFromPath(screenshotPath);
// 步骤4:验证结果(新增日志)
_currentTest.Log(Status.Info, "验证是否进入主页面");
var homeTitle = _mainWindow.WaitUntilExists(cf => cf.ByAutomationId("HomePage_Title"), TimeSpan.FromSeconds(5))?.AsTextBlock();
Assert.IsNotNull(homeTitle, "登录后未进入主页面");
_currentTest.Log(Status.Pass, "登录成功,主页面显示正常");
}
catch (Exception ex)
{
// 测试失败时,捕获截图并记录日志
var errorScreenshot = Capture.Screenshot(_mainWindow);
var errorScreenshotPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestResults", $"{TestContext.CurrentContext.Test.Name}_error.png");
errorScreenshot.Save(errorScreenshotPath);
_currentTest.AddScreenCaptureFromPath(errorScreenshotPath);
_currentTest.Log(Status.Fail, $"测试失败:{ex.Message}");
throw; // 抛出异常,让NUnit标记测试失败
}
}
// 【全局清理】生成报告
[OneTimeTearDown]
public void GlobalTearDown()
{
// 原有逻辑...
// 生成Extent报告
_extentReport.Flush();
}
3. 查看测试报告
测试运行完成后:
- 打开测试项目的
TestResults文件夹 - 双击
Extent_Report.html→ 用浏览器打开(可看到带截图、步骤日志的可视化报告)
四、通用调试工具:FlaUInspect 的使用
FlaUInspect 是 FlaUI 官方的控件查看工具,能帮你快速获取控件的AutomationId:
- 下载:在 GitHub 搜索
FlaUInspect→ 下载最新版本的 exe - 使用步骤:
- 打开被测 WPF 程序
- 打开 FlaUInspect → 点击左上角「Select Application」→ 选择你的 WPF 程序进程
- 点击 FlaUInspect 的「Pick」按钮 → 鼠标移到 WPF 界面的控件上(如账号输入框)
- 在 FlaUInspect 的「Properties」面板中,找到
AutomationId(直接复制用于测试代码)