Go+chromedp实现Web UI自动化测试

1.为什么使用go进行UI自动化测试?

速度:Go速度很快,这在运行包含数百个UI测试的测试套件时是一个巨大的优势

并发性:可以利用Go的内置并发性(goroutines)来并行化测试执行

简单:Go的简约语法允许您编写可读且可维护的测试脚本

ChromeDP:一个无头Chrome/Chromium库,允许直接从Go控制浏览器

2.什么是chromedp?

ChromeDP 是一个 Go 库,允许开发者通过 Chrome DevTools 协议控制 Chrome/Chromium。借助 ChromeDP,您可以与网页交互、模拟用户输入、浏览浏览器以及提取内容进行验证。它既可以在无头模式(没有浏览器UI)下工作,也可以在有头模式(有可见浏览器)下工作。

3.设置环境

安装go

bash 复制代码
brew install go

安装ChromeDP

bash 复制代码
go get -u github.com/chromedp/chromedp

4.编写代码

示例测试

打开GoLand,新建main.go文件

main.go-核心测试

这段代码将会打开Chrome,导航到Google搜索页,搜索"Golang",并验证Golang是否出现在搜索结果中

Go 复制代码
package main

import (
   "context"
   "fmt"
   "github.com/chromedp/chromedp"
   "github.com/chromedp/chromedp/kb"
   "log"
   "strings"
   "time"
)

func main() {
   opts := chromedp.DefaultExecAllocatorOptions[:]
   opts = append(opts,
      // Disable headless mode
      chromedp.Flag("headless", false),
      // Enable GPU (optional)
      chromedp.Flag("disable-gpu", false),
      // Start with a maximized window
      chromedp.Flag("start-maximized", true),
   )
   allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
   defer cancel()
   ctx, cancel := chromedp.NewContext(allocCtx)
   defer cancel()
   ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
   defer cancel()
   var result string
   err := chromedp.Run(ctx,
      chromedp.Navigate("https://www.google.com"),
      chromedp.WaitVisible(`//textarea[@name="q"]`),
      chromedp.SendKeys(`//textarea[@name="q"]`, "Golang"),
      chromedp.SendKeys(`//textarea[@name="q"]`, kb.Enter),
      chromedp.WaitVisible(`#search`),
      chromedp.Text(`#search`, &result),
   )
   if err != nil {
      log.Fatal(err)
   }
   if strings.Contains(result, "Golang") {
      fmt.Println("Test Passed: 'Golang' found in search results")
   } else {
      fmt.Println("Test Failed: 'Golang' not found in search results")
   }
}

Go测试框架编写多个UI测试

新建main_test.go文件

main_test.go-多种测试结果

测试用例:

  1. 检查搜索结果是否包含术语"Golang"
  2. 验证搜索栏是否在 Google 主页上可见
  3. 检查空查询是否会导致没有搜索结果
Go 复制代码
package main

import (
   "context"
   "github.com/chromedp/chromedp"
   "github.com/chromedp/chromedp/kb"
   "strings"
   "testing"
   "time"
)

// checks that the search results contain "Golang"
func TestGoogleSearch_Golang(t *testing.T) {
   opts := chromedp.DefaultExecAllocatorOptions[:]
   opts = append(opts,
      chromedp.Flag("headless", false),
      chromedp.Flag("disable-gpu", false),
      chromedp.Flag("start-maximized", true),
   )
   allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
   defer cancel()
   ctx, cancel := chromedp.NewContext(allocCtx)
   defer cancel()
   ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
   defer cancel()
   var result string
   err := chromedp.Run(ctx,
      chromedp.Navigate("https://www.google.com"),
      chromedp.WaitVisible(`//textarea[@name="q"]`),
      chromedp.SendKeys(`//textarea[@name="q"]`, "Golang"),
      chromedp.SendKeys(`//textarea[@name="q"]`, kb.Enter),
      chromedp.WaitVisible(`#search`),
      chromedp.Text(`#search`, &result),
   )
   if err != nil {
      t.Fatalf("Test Failed: %v", err)
   }
   if strings.Contains(result, "Golang") {
      t.Log("Test Passed: 'Golang' found in search results")
   } else {
      t.Errorf("Test Failed: 'Golang' not found in search results")
   }
}

// checks that the search bar is visible
func TestGoogleSearch_SearchBarVisible(t *testing.T) {
   opts := chromedp.DefaultExecAllocatorOptions[:]
   opts = append(opts,
      chromedp.Flag("headless", false),
      chromedp.Flag("disable-gpu", false),
      chromedp.Flag("start-maximized", true),
   )
   allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
   defer cancel()
   ctx, cancel := chromedp.NewContext(allocCtx)
   defer cancel()
   ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
   defer cancel()
   err := chromedp.Run(ctx,
      chromedp.Navigate("https://www.google.com"),
      chromedp.WaitVisible(`//textarea[@name="q"]`),
   )
   if err != nil {
      t.Errorf("Test Failed: Search bar not visible - %v", err)
   } else {
      t.Log("Test Passed: Search bar is visible")
   }
}

// checks if there are results when the search query is empty
func TestGoogleSearch_EmptyQuery(t *testing.T) {
   opts := chromedp.DefaultExecAllocatorOptions[:]
   opts = append(opts,
      chromedp.Flag("headless", false),
      chromedp.Flag("disable-gpu", false),
      chromedp.Flag("start-maximized", true),
   )
   allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
   defer cancel()
   ctx, cancel := chromedp.NewContext(allocCtx)
   defer cancel()
   ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
   defer cancel()
   var result string
   err := chromedp.Run(ctx,
      chromedp.Navigate("https://www.google.com"),
      chromedp.WaitVisible(`//textarea[@name="q"]`),
      chromedp.SendKeys(`//textarea[@name="q"]`, ""), // Empty query
      chromedp.SendKeys(`//textarea[@name="q"]`, kb.Enter),
      chromedp.WaitVisible(`#search`, chromedp.ByID),
      chromedp.Text(`#search`, &result),
   )
   if err != nil {
      t.Fatalf("Test Failed: %v", err)
   }
   if result == "" {
      t.Log("Test Passed: No search results for empty query")
   } else {
      t.Errorf("Test Failed: Unexpected results for empty query")
   }
}

执行测试

将main.go和main_test.go放在同一目录,然后执行命令

bash 复制代码
go test -v

测试结果

相关推荐
ttwuai7 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
布朗克16811 小时前
Go 入门到精通-31-编码与序列化
开发语言·qt·golang·编码与序列化
microrain14 小时前
从硬编码到热插拔:SagooIoT插件架构如何打破物联网平台的扩展瓶颈
物联网·golang·开源·sagooiot
geovindu15 小时前
go:Backtracking Algorithm
开发语言·后端·算法·golang·回溯算法
qq_4523962316 小时前
第六篇:《并发编程核心:Goroutine 与 Channel》
golang
llwszx16 小时前
【Java/Go后端手撸原生Agent(第五篇):多工具并行调用 + BashTool执行引擎 + Judge证据链升级】
java·后端·golang·状态机·pydantic·agnet·llm-as-judge
FfHUCisI16 小时前
Go语言程序结构 —— 变量、声明与零值机制
golang
超人不会飞_Jay17 小时前
Go课程2
开发语言·后端·golang
晴空了无痕1 天前
从 Go 基础到 K8s:一条可落地的 Go 服务端成长路线
开发语言·后端·golang·kubernetes
qq_452396231 天前
第五篇:《接口与错误处理:Go 的哲学》
开发语言·后端·golang