TA的每日心情 | 无聊 13 小时前 |
---|
签到天数: 1050 天 连续签到: 1 天 [LV.10]测试总司令
|
获取图片
思路一样,区别是我们需要获取二进制的图片数据了,这里需要用到 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 文件就包含了要爬的图片:
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 文件就包含了要爬的图片:
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 也是很不错的参考资料。
|
|