这个Skill在干嘛
做.NET MAUI开发的同学应该都懂那种痛——PR提上去了,reviewer问你测试呢?然后你对着GitHub Issue发呆,不知道怎么把bug复现成一个能跑的UI测试。Write UI Tests这个Skill就是专门解决这个问题的,它能根据Issue自动生成HostApp页面和NUnit测试文件,而且有个硬核设计:测试必须先跑失败,才算完成。
这个逻辑其实很对——一个在bug修复前就能通过的测试,根本证明不了它能捕获这个bug。Skill会强制验证测试失败,确保你写的测试是真的有效的,而不是走个形式。
核心功能
- 自动生成HostApp页面:在
TestCases.HostApp/Issues/目录下创建带有正确[Issue()]属性和AutomationId的C#页面,UI最小化,只保留复现bug所需的元素。 - 自动生成NUnit测试:在
TestCases.Shared.Tests/Tests/Issues/下生成继承自_IssuesUITest的测试类,包含App.WaitForElement()、App.Tap()等Appium操作。 - 强制失败验证:调用
verify-tests-fail.ps1脚本,确认测试在没有修复的情况下确实失败,最多迭代3次,超过则主动询问用户。 - 跨平台支持:支持Android、iOS、MacCatalyst,会根据Issue标签自动选择优先测试的平台。
- 编译验证:生成文件后自动执行
dotnet build确认代码能编译通过,再进行测试运行。
适用平台
Write UI Tests作为一个标准的Agent Skill文件,可以无缝接入主流AI编程助手,成为你IDE里的最强外挂。无论是Cursor、GitHub Copilot、Claude Code还是OpenAI Codex,只要把这个Skill加载进去,AI就能获得完整的.NET MAUI UI测试规范上下文,生成的代码直接符合项目约定,不用再手动对照文档改格式。Gemini Code Assist、文心快码、腾讯云CodeBuddy、华为云CodeArts同样适用,显著提升AI对测试文件结构、命名规范和Appium操作模式的理解能力,让你少走弯路。
实操代码示例
下面是Skill生成的HostApp页面和NUnit测试的典型结构,直接拿来参考:
// HostApp页面:TestCases.HostApp/Issues/Issue33331.cs
namespace Maui.Controls.Sample.Issues;
[Issue(IssueTracker.Github, 33331, "Button click does not update label", PlatformAffected.All)]
public partial class Issue33331 : ContentPage
{
public Issue33331()
{
var button = new Button
{
Text = "Test Button",
AutomationId = "TestButton"
};
var resultLabel = new Label
{
Text = "Waiting...",
AutomationId = "ResultLabel"
};
button.Clicked += (s, e) => resultLabel.Text = "Success";
Content = new VerticalStackLayout { Children = { button, resultLabel } };
}
}
// NUnit测试:TestCases.Shared.Tests/Tests/Issues/Issue33331.cs
namespace Microsoft.Maui.TestCases.Tests.Issues;
public class Issue33331 : _IssuesUITest
{
public override string Issue => "Button click does not update label";
public Issue33331(TestDevice device) : base(device) { }
[Test]
[Category(UITestCategories.Button)]
public void ButtonClickUpdatesLabel()
{
App.WaitForElement("TestButton");
App.Tap("TestButton");
var labelText = App.FindElement("ResultLabel").GetText();
Assert.That(labelText, Is.EqualTo("Success"));
}
}
运行验证脚本确认测试失败:
pwsh .github/skills/verify-tests-fail-without-fix/scripts/verify-tests-fail.ps1 -Platform android -TestFilter "Issue33331"
优势分析
市面上大多数测试生成工具只管生成,不管有没有用。Write UI Tests的核心差异点在于强制失败验证机制——它不允许你用一个永远通过的测试糊弄过去。这个设计直接对齐了TDD的核心思想:先写失败的测试,再写修复代码。
- 零配置上手:只需要提供Issue编号、描述和受影响平台,Skill自动处理文件路径、命名规范、属性格式,不用翻文档。
- 内置迭代逻辑:测试通过时不会直接报完成,而是主动分析可能的原因并尝试修正,最多3次迭代后才会请求人工介入。
- 平台感知:根据Issue标签智能选择测试平台,Android优先(模拟器启动快),iOS/MacCatalyst按需切换,减少无效等待。
- 编译前置验证:先build再跑测试,避免因语法错误浪费测试运行时间。
应用场景
- PR审查前补测试:代码写完了但没有对应的UI测试,直接丢Issue编号给Skill,几分钟内生成可运行的测试文件。
- Bug复现存档:产品反馈了一个偶现问题,用Write UI Tests把复现步骤固化成自动化测试,后续回归不再靠手动。
- 新人上手项目:不熟悉.NET MAUI测试规范的开发者,通过Skill生成的代码直接学习标准写法,比看文档效率高得多。
- 跨平台回归验证:同一个bug在Android和iOS表现不同,Skill支持分平台生成和验证,覆盖更全面。
最佳实践
用Write UI Tests时有几个工程化细节值得注意。AutomationId命名要语义化,别用Button1这种,用SubmitButton、ErrorLabel这类能表达意图的名字,测试代码可读性会好很多,后续维护也省心。
每个测试只验证一个行为,不要在一个测试方法里塞多个断言场景。Write UI Tests生成的模板已经遵循这个原则,自己扩展时也要保持。
异步和动画场景要用retryTimeout,直接用App.WaitForElement()加超时参数,或者用VerifyScreenshot(retryTimeout: TimeSpan.FromSeconds(2))处理动画完成后的截图对比,避免因时序问题导致测试不稳定。
平台特定bug优先在对应平台验证,Issue标签写了iOS就先跑iOS,不要默认全平台,节省CI时间。如果一个平台通过了另一个失败,说明bug有平台差异,需要在测试里加平台判断或者拆成两个测试。
对于需要管理大量Skill文件、统一维护团队AI工具链的场景,Skill优仓提供了一个集中存储和分发Skill的平台,团队成员可以直接从Skill优仓拉取经过验证的Skill文件,避免每个人重复配置,保持工程规范一致。









暂无评论内容