51Testing软件测试论坛
标题:
Web测试好帮手Rod(三)
[打印本页]
作者:
lsekfe
时间:
2022-11-3 14:20
标题:
Web测试好帮手Rod(三)
获取图片
思路一样,区别是我们需要获取二进制的图片数据了,这里需要用到 Element 的MustResource方法:
<font size="3">// MustResource is similar to Element.Resource
func (el *Element) MustResource() []byte {
bin, err := el.Resource()
el.e(err)
return bin
}
// Resource returns the "src" content of current element. Such as the jpg of <img src="a.jpg">
func (el *Element) Resource() ([]byte, error) {
src, err := el.Evaluate(evalHelper(js.Resource).ByPromise())
if err != nil {
return nil, err
}
return el.page.GetResource(src.Value.String())
}</font>
复制代码
这里会返回一个字节数组,需要我们进行转换。rod 的 util 包也提供了相关方法:
<font size="3">// OutputFile auto creates file if not exists, it will try to detect the data type and
// auto output binary, string or json
func OutputFile(p string, data interface{}) error {
dir := filepath.Dir(p)
_ = Mkdir(dir)
var bin []byte
switch t := data.(type) {
case []byte:
bin = t
case string:
bin = []byte(t)
case io.Reader:
f, _ := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
_, err := io.Copy(f, t)
return err
default:
bin = MustToJSONBytes(data)
}
return ioutil.WriteFile(p, bin, 0664)
}</font>
复制代码
这里接收的 data 就可以是个字节数组,p 是文件输出路径。OutputFile 会自行处理创建目录,文件,写入数据的流程。下面我们改下代码看看:
<font size="3">package main
import (
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/utils"
)
func main() {
page := rod.New().MustConnect().MustPage("https://www.wikipedia.org/")
page.MustElement("#searchInput").MustInput("earth")
page.MustElement("#search-form > fieldset > button").MustClick()
el := page.MustElement("#mw-content-text > div.mw-parser-output > table.infobox > tbody > tr:nth-child(1) > td > a > img")
_ = utils.OutputFile("b.png", el.MustResource())
}</font>
复制代码
重新运行后,我们的 b.png 文件就包含了要爬的图片:
[attach]144622[/attach]
E2E 示例
这一节我们来看看官方给出的 E2E 示例。真实的业务场景远比这个复杂,但本质内核都是一样的,大家可以结合相关 API 设计自己的 E2E 流程。
https://ahfarmer.github.io/calculator/
是一个经典的在线计算器,大家可以自己打开看一看,页面非常简单,模拟大家手机的计算器 app。
假定我们是这个计算器的开发者,希望做端到端测试,就可以借助 rod 的能力,直接在网页上操作加减法,看看最终结果是否符合预期。
为此,我们还需要借助一些测试框架的断言能力,比较结果。这里官方是用了作者自己的测试库:"github.com/ysmood/got",大家有需求的话其实可以替换成自己常用的。
第一步,我们需要先创建出一个 Browser 对象,毕竟 E2E 不可能只测几个单独的case,也需要支持并发。这里可以使用一个共用的 Browser 对象。新建一个 setup_test.go,填充以下内容:
<font size="3">// This is the setup file for this test suite.
package main
import (
"testing"
"github.com/go-rod/rod"
"github.com/ysmood/got"
)
// test context
type G struct {
got.G
browser *rod.Browser
}
// setup for tests
var setup = func() func(t *testing.T) G {
browser := rod.New().MustConnect()
return func(t *testing.T) G {
t.Parallel() // run each test concurrently
return G{got.New(t), browser}
}
}()
// a helper function to create an incognito page
func (g G) page(url string) *rod.Page {
page := g.browser.MustIncognito().MustPage(url)
g.Cleanup(page.MustClose)
return page
}</font>
复制代码
这里的 page 也是默认开启无痕模式,打开指定的 url,利用了 ysmood/got 的 Cleanup 能力随后进行清理,本质是个 helper 函数。
第二步,开始校验业务逻辑,新建 calculator_test.go,填充以下内容:
<font size="3">// Package main ...
package main
import "testing"
// test case: 1 + 2 = 3
func TestAdd(t *testing.T) {
g := setup(t)
p := g.page("https://ahfarmer.github.io/calculator")
p.MustElementR("button", "1").MustClick()
p.MustElementR("button", `^\+[b][size=3]获取图片[/size][/b]
[size=3] 思路一样,区别是我们需要获取二进制的图片数据了,这里需要用到 Element 的MustResource方法:[/size]
[code]<font size="3">// MustResource is similar to Element.Resource
func (el *Element) MustResource() []byte {
bin, err := el.Resource()
el.e(err)
return bin
}
// Resource returns the "src" content of current element. Such as the jpg of <img src="a.jpg">
func (el *Element) Resource() ([]byte, error) {
src, err := el.Evaluate(evalHelper(js.Resource).ByPromise())
if err != nil {
return nil, err
}
return el.page.GetResource(src.Value.String())
}</font>
复制代码
这里会返回一个字节数组,需要我们进行转换。rod 的 util 包也提供了相关方法:
<font size="3">// OutputFile auto creates file if not exists, it will try to detect the data type and
// auto output binary, string or json
func OutputFile(p string, data interface{}) error {
dir := filepath.Dir(p)
_ = Mkdir(dir)
var bin []byte
switch t := data.(type) {
case []byte:
bin = t
case string:
bin = []byte(t)
case io.Reader:
f, _ := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
_, err := io.Copy(f, t)
return err
default:
bin = MustToJSONBytes(data)
}
return ioutil.WriteFile(p, bin, 0664)
}</font>
复制代码
这里接收的 data 就可以是个字节数组,p 是文件输出路径。OutputFile 会自行处理创建目录,文件,写入数据的流程。下面我们改下代码看看:
<font size="3">package main
import (
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/utils"
)
func main() {
page := rod.New().MustConnect().MustPage("https://www.wikipedia.org/")
page.MustElement("#searchInput").MustInput("earth")
page.MustElement("#search-form > fieldset > button").MustClick()
el := page.MustElement("#mw-content-text > div.mw-parser-output > table.infobox > tbody > tr:nth-child(1) > td > a > img")
_ = utils.OutputFile("b.png", el.MustResource())
}</font>
复制代码
重新运行后,我们的 b.png 文件就包含了要爬的图片:
[attach]144622[/attach]
E2E 示例
这一节我们来看看官方给出的 E2E 示例。真实的业务场景远比这个复杂,但本质内核都是一样的,大家可以结合相关 API 设计自己的 E2E 流程。
https://ahfarmer.github.io/calculator/
是一个经典的在线计算器,大家可以自己打开看一看,页面非常简单,模拟大家手机的计算器 app。
假定我们是这个计算器的开发者,希望做端到端测试,就可以借助 rod 的能力,直接在网页上操作加减法,看看最终结果是否符合预期。
为此,我们还需要借助一些测试框架的断言能力,比较结果。这里官方是用了作者自己的测试库:"github.com/ysmood/got",大家有需求的话其实可以替换成自己常用的。
第一步,我们需要先创建出一个 Browser 对象,毕竟 E2E 不可能只测几个单独的case,也需要支持并发。这里可以使用一个共用的 Browser 对象。新建一个 setup_test.go,填充以下内容:
<font size="3">// This is the setup file for this test suite.
package main
import (
"testing"
"github.com/go-rod/rod"
"github.com/ysmood/got"
)
// test context
type G struct {
got.G
browser *rod.Browser
}
// setup for tests
var setup = func() func(t *testing.T) G {
browser := rod.New().MustConnect()
return func(t *testing.T) G {
t.Parallel() // run each test concurrently
return G{got.New(t), browser}
}
}()
// a helper function to create an incognito page
func (g G) page(url string) *rod.Page {
page := g.browser.MustIncognito().MustPage(url)
g.Cleanup(page.MustClose)
return page
}</font>
复制代码
这里的 page 也是默认开启无痕模式,打开指定的 url,利用了 ysmood/got 的 Cleanup 能力随后进行清理,本质是个 helper 函数。
第二步,开始校验业务逻辑,新建 calculator_test.go,填充以下内容:
).MustClick()
p.MustElementR("button", "2").MustClick()
p.MustElementR("button", "=").MustClick()
// assert the result with t.Eq
g.Eq(p.MustElement(".component-display").MustText(), "3")
}
// test case: 2 * 3 = 6
func TestMultiple(t *testing.T) {
g := setup(t)
p := g.page("https://ahfarmer.github.io/calculator")
// use for-loop to click each button
for _, regex := range []string{"2", "x", "3", "="} {
p.MustElementR("button", regex).MustClick()
}
g.Eq(p.MustElement(".component-display").MustText(), "6")
}</font>[/code]
这里只是示例,case 比较简单。大家可以自行调整一下试试。
第一个case我们需要校验加法是否正常我们打开计算器网页,通过 MustElementR 获取到指定元素,触发点击。
<font size="3">// MustElementR is similar to Page.ElementR
func (p *Page) MustElementR(selector, jsRegex string) *Element {
el, err := p.ElementR(selector, jsRegex)
p.e(err)
return el
}
// ElementR retries until an element in the page that matches the css selector and it's text matches the jsRegex,
// then returns the matched element.
func (p *Page) ElementR(selector, jsRegex string) (*Element, error) {
return p.ElementByJS(evalHelper(js.ElementR, selector, jsRegex))
}</font>
复制代码
这里的 MustElementR 补充了正则能力,毕竟有些元素单独靠 selector 无法定位,这里是增强的能力。
触发元素点击后,通过断言,判断文本和指定的结果是否匹配即可。
第二个 case 也是类似的场景,大家可以由此体会一下 MustElementR 的用法。
执行测试case和平常的 Golang 单测没有区别,直接 go test 命令即可。
小结
这里我们只是拿出来 rod 常见的一些用法,它可以打印,可以转图片,截屏,导出 pdf。可以模拟人为的浏览器操作,整体功能还是非常强大的,建议大家自己动手试一下。官方的 guide 也是很不错的参考资料。
欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/)
Powered by Discuz! X3.2