Skip to content

测试 ​

ui.NewTester 在没有窗口的情况下运行视图,快得像单元测试:它在内存中 渲染帧,按文本查找元素,并执行点击、输入、滚动和按键。

go
func TestCounter(t *testing.T) {
	app := &counter{}
	tt := ui.NewTester(app.view, 320, 240)
	if err := tt.Click("Increment"); err != nil {
		t.Fatal(err)
	}
	if app.n != 1 || !tt.HasText("1") {
		t.Errorf("count %d, texts %q", app.n, tt.Texts())
	}
}

元素按文本查找;没有文本的元素(如图标按钮)按 Label 查找: tt.Click("Close")、tt.Find("Volume")、tt.Focused("Name")。

同一父元素下两个使用相同 Key 的元素共享一个状态,因此针对其中一个的 点击或焦点会落到另一个身上:测试器会在给出第二个键的地方 panic,而 应用只是记录日志。

测试器的功能 ​

  • 指针。 tt.Click、tt.ClickAt、tt.ClickWith(ui.Shift, "Row 3")、 tt.Press、tt.Move 和 tt.Release、tt.Scroll(像触控板那样立即 滚动),以及 tt.Wheel(鼠标滚轮的一格,随着时钟推进平滑滑过去, 参见 tt.Advance)。

  • 键盘。 tt.Key(ui.Cmd, ui.KeyS) 按下一个键,tt.TypeKey 按下键 并同时输入文本,tt.Type 向获得焦点的元素输入文本。tt.Compose 模拟输入法的组合过程,tt.Command 执行菜单中的编辑命令,例如 "copy",tt.TextCaret 返回输入法将组合文本的位置。

  • 菜单。 tt.RightClick 打开上下文菜单,tt.Menu 列出其条目, tt.ChooseMenuItem("Move to", "Archive") 从中选择。

  • 窗口。 tt.SetSize、tt.SetScale、tt.SetZoom(内容的 缩放,与 Context.SetZoom 相同;测试器的坐标—— Find、ClickAt、Move 和 TextCaret 使用的——始终是窗口的坐标)、 tt.SetDark、tt.SetPreferences 和 tt.SetDirection(按 从右到左布局)更改窗口和桌面设置; tt.SetFocused 从窗口取走键盘焦点并归还。

  • 可见内容。 tt.Texts、tt.HasText、tt.Find(某段文本的盒子)、 tt.Focused、tt.Cursor、tt.Clipboard、tt.OpenedURLs 和 tt.Announcements(视图请求屏幕阅读器朗读的内容);tt.FailOpenURL 让它打开的链接失败,就像应用无法打开的链接那样。

  • 帧。 tt.Frame 绘制一帧,用于视图外部发生的变化;tt.Image() 返回最后一帧,用于快照;ui.Render 以给定缩放绘制视图一次。输入和 tt.Frame 会运行视图请求的帧,直到它不再请求,或最多 20 帧: tt.FramePending 告知它是否仍在请求,就像一直在做动画或永不静止的 视图那样。

  • 时间。 测试器有自己的时钟 tt.Now(),它保持静止,直到 tt.Advance(d) 把它向前推进 d,并按时运行期间到期的帧:有东西在 移动时每次刷新运行一帧,以及 c.After 和 Painter.After 到期时的 那些。依赖时间的事情都跟着它走:动画、Context.After、Context.Now、 组成双击的点击、合并为一步撤销的输入、光标闪烁、工具提示和提示条。 因此,测试在繁忙的机器上和在快速的机器上结果相同:永远不要靠 sleep 等某事发生,而是推进时钟。Advance 只运行视图请求的帧:从视图外部 改变它所显示的内容后,先调用 tt.Frame。editor.Buffer 和 richtext.Document 的撤销步骤使用系统时钟。

    go
    tt := ui.NewTester(app.view, 320, 240)
    tt.Click("More")
    tt.Advance(100 * time.Millisecond) // 200 毫秒动画进行到一半
    tt.Advance(time.Second)            // 动画结束
    if tt.FramePending() {
    	t.Error("the panel keeps asking for frames")
    }

测试构建后的应用 ​

测试器在 go test 内运行视图。要像端到端测试运行器或智能体那样,从 另一个进程测试按构建产物运行的应用及其真实窗口,请在测试构建中引入 automation 插件:它像测试器的 Find 那样 读取每个窗口的元素,按其标签或 Key 查找,对它们执行操作,发送输入, 并在 FramePending 指示仍有帧时等待。