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

测试结果

相关推荐
紧跟先前的步伐21 小时前
Go AI Agent 实战 22|完善 Agent 执行循环:从工具调用到最终回答
人工智能·ai·golang
后台模板学习1 天前
Go Web开发中任务调度框架的源码解析与高可用实现方案
开发语言·后端·golang
FungLeo1 天前
成为全栈·Go 后端篇·分类树与标签关系:目录变更为何需要协调
golang·go·gorm·数据库事务·分类树·成为全栈
fly-iot1 天前
【FDE知识库】(1):AI 编程时代开发语言选型分析,云使用go,企业用java,算法python,底层c
开发语言·人工智能·golang
FungLeo1 天前
成为全栈·Go 后端篇·文章查询与展示投影:安全分页、排序和软删除
golang·go·gorm·分页查询·成为全栈·sql安全
紧跟先前的步伐1 天前
Go AI Agent 实战 24|工具系统工程化收尾与阶段验收
人工智能·ai·golang·1024程序员节
日日大王学编程1 天前
#Feed 流项目复盘:Redis 时间线缓存与 Outbox 消息可靠性设计
golang·1024程序员节
北冥you鱼2 天前
Go 语言 CRUD 实战:从接口设计到真实业务场景
开发语言·后端·golang
利威尔xu2 天前
Go IM 源码实战(11):token 只是个 HASH,多端互踢的顺序错了就踢错人
后端·微服务·面试·架构·golang
microrain2 天前
SagooIoT 把协议解析和消息通知都放进了独立进程
物联网·golang·插件·sagooiot