用途
该技能用于指导为 WinForms 控件或组件新增的公共属性、方法、事件和虚拟方法编写单元测试。它适用于 API 实现完成后的测试环节;API 实现本身另见 new-control-api 技能。
核心原则:每个新增公共 API 成员都需要测试,验证默认值、get/set 往返、事件触发、事件幂等性,以及在有和没有原生窗口句柄两种情况下的行为。
测试项目结构
控件测试位于:
src\test\unit\System.Windows.Forms\System\Windows\Forms\
测试项目文件为:
src\test\unit\System.Windows.Forms\System.Windows.Forms.Tests.csproj
每个控件有各自的测试文件(或一组 partial 文件),例如 Button 对应 ButtonTests.cs,ButtonBase 对应 ButtonBaseTests.cs,Control 对应 ControlTests.cs、ControlTests.Handlers.cs,Form 对应 FormTests.cs,TextBox 对应 TextBoxTests.cs。新增 API 测试应加入该控件已有的测试文件;若文件已过大,可使用新的 partial 文件,命名为 {Control}Tests.{Feature}.cs。
项目使用 xUnit 与 FluentAssertions。关键特性包括:[WinFormsFact](单测试用例,STA 线程感知的 [Fact])和 [WinFormsTheory](参数化测试,STA 线程感知的 [Theory])。这些自定义 xUnit 特性确保测试在 STA 线程上运行,这是 WinForms 进行 COM 互操作和 UI 操作所必需的。
测试方法命名
遵循模式:{ControlName}{MemberName}{Scenario}。示例:Button_DialogResult_Set_GetReturnsExpected、Control_OnAutoSizeChanged_Invoke_CallsAutoSizeChanged、ButtonBase_Command_SetWithHandler_CallsCommandChanged、Control_DataContext_AmbientBehaviorTest。
控件创建与释放
始终使用 using 声明,确保控件被正确释放,释放原生窗口句柄和 GDI 资源。
SubControl 模式
受保护成员(OnXxx 方法、受保护属性)无法在测试中直接调用。可在测试类内创建私有嵌套子类,使用 new 暴露它们。规则:子类为私有并嵌套在测试类内;使用 public new 重新暴露受保护的基类成员;命名为 Sub{ControlName}(如 SubButton、SubControl)。访问私有成员可使用 TestAccessor:this.TestAccessor.Dynamic.PrivateMethod()。
测试数据特性
使用内置测试数据特性避免手工编写值集:[BoolData] 生成 true、false;[EnumData<TEnum>] 生成枚举所有值;[NewAndDefaultData<EventArgs>] 生成 new EventArgs()、EventArgs.Empty;[InlineData(...)] 显式内联值;[MemberData(nameof(...))] 来自静态属性/方法的值。
必需测试类别
对每个新增公共属性,需提供以下类别测试:
-
默认值测试:验证属性在构造后、创建句柄前立即返回预期默认值。
-
属性 set/get 往返(无句柄):设置后读取应返回预期值,且未创建句柄;再次设置相同值必须幂等。
-
属性 set/get 往返(有句柄):强制创建句柄,验证无意外副作用事件(如 Invalidated、StyleChanged、HandleCreated 计数为 0)。
-
事件触发测试:验证值变化时 [Property]Changed 事件触发,设置相同值时不触发,移除处理器后不再触发。
-
OnXxx 虚拟方法测试:通过 SubControl 直接测试 On[Property]Changed 方法,验证其引发事件且可取消订阅。
-
OnXxx 虚拟方法测试(有句柄):若 On 方法触发视觉变化(失效、样式变化),需在有句柄情况下测试。
自定义 EventArgs 与委托测试
当 API 引入专用 EventArgs 子类和委托时,测试应验证 sender、事件参数对象及自定义属性(如 e.Detail)的正确性。
ICommand 命令绑定测试
若新 API 涉及 ICommand 绑定,需测试完整生命周期:绑定命令、设置参数、执行、禁用命令。
新 API 测试检查清单
- 默认值测试(构造函数,无句柄)
- 属性 set/get 往返(无句柄)
- 属性 set/get 往返(有句柄,验证副作用事件)
- 值变化时事件触发
- 事件幂等性(相同值 → 不触发事件)
- 事件处理器移除(取消订阅 → 不触发事件)
- OnXxx 虚拟方法直接调用(通过 SubControl)
- OnXxx 有句柄(若触发失效)
- 自定义 EventArgs 属性断言(如适用)
- 所有控件实例使用 using 声明
- 在不应强制创建句柄处断言 Assert.False(control.IsHandleCreated)
适用场景与限制
该技能适用于 .NET WinForms 仓库中为控件和组件新增公共 API 时编写单元测试。它假定使用 xUnit、FluentAssertions 以及仓库自定义的 STA 线程感知测试特性。资料未提供关于其他测试框架、其他平台或非 WinForms 场景的说明。