51Testing软件测试论坛

标题: Web测试好帮手Rod(三) [打印本页]

作者: lsekfe    时间: 2022-11-3 14:20
标题: Web测试好帮手Rod(三)
获取图片
  思路一样,区别是我们需要获取二进制的图片数据了,这里需要用到 Element 的MustResource方法:
  1. <font size="3">// MustResource is similar to Element.Resource

  2. func (el *Element) MustResource() []byte {

  3. bin, err := el.Resource()

  4. el.e(err)

  5. return bin

  6. }




  7. // Resource returns the "src" content of current element. Such as the jpg of <img src="a.jpg">

  8. func (el *Element) Resource() ([]byte, error) {

  9. src, err := el.Evaluate(evalHelper(js.Resource).ByPromise())

  10. if err != nil {

  11. return nil, err

  12. }




  13. return el.page.GetResource(src.Value.String())

  14. }</font>
复制代码


这里会返回一个字节数组,需要我们进行转换。rod 的 util 包也提供了相关方法:


  1. <font size="3">// OutputFile auto creates file if not exists, it will try to detect the data type and

  2. // auto output binary, string or json

  3. func OutputFile(p string, data interface{}) error {

  4. dir := filepath.Dir(p)

  5. _ = Mkdir(dir)




  6. var bin []byte




  7. switch t := data.(type) {

  8. case []byte:

  9. bin = t

  10. case string:

  11. bin = []byte(t)

  12. case io.Reader:

  13. f, _ := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)

  14. _, err := io.Copy(f, t)

  15. return err

  16. default:

  17. bin = MustToJSONBytes(data)

  18. }




  19. return ioutil.WriteFile(p, bin, 0664)

  20. }</font>
复制代码


这里接收的 data 就可以是个字节数组,p 是文件输出路径。OutputFile 会自行处理创建目录,文件,写入数据的流程。下面我们改下代码看看:


  1. <font size="3">package main




  2. import (

  3.     "github.com/go-rod/rod"

  4.     "github.com/go-rod/rod/lib/utils"

  5. )




  6. func main() {

  7.     page := rod.New().MustConnect().MustPage("https://www.wikipedia.org/")




  8.     page.MustElement("#searchInput").MustInput("earth")

  9.     page.MustElement("#search-form > fieldset > button").MustClick()




  10.     el := page.MustElement("#mw-content-text > div.mw-parser-output > table.infobox > tbody > tr:nth-child(1) > td > a > img")

  11.     _ = utils.OutputFile("b.png", el.MustResource())

  12. }</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,填充以下内容:



  1. <font size="3">// This is the setup file for this test suite.




  2. package main




  3. import (

  4. "testing"




  5. "github.com/go-rod/rod"

  6. "github.com/ysmood/got"

  7. )




  8. // test context

  9. type G struct {

  10. got.G




  11. browser *rod.Browser

  12. }




  13. // setup for tests

  14. var setup = func() func(t *testing.T) G {

  15. browser := rod.New().MustConnect()




  16. return func(t *testing.T) G {

  17. t.Parallel() // run each test concurrently




  18. return G{got.New(t), browser}

  19. }

  20. }()




  21. // a helper function to create an incognito page

  22. func (g G) page(url string) *rod.Page {

  23. page := g.browser.MustIncognito().MustPage(url)

  24. g.Cleanup(page.MustClose)

  25. return page

  26. }</font>
复制代码


这里的 page 也是默认开启无痕模式,打开指定的 url,利用了 ysmood/got 的 Cleanup 能力随后进行清理,本质是个 helper 函数。
  第二步,开始校验业务逻辑,新建 calculator_test.go,填充以下内容:



  1. <font size="3">// Package main ...

  2. package main




  3. import "testing"




  4. // test case: 1 + 2 = 3

  5. func TestAdd(t *testing.T) {

  6. g := setup(t)




  7. p := g.page("https://ahfarmer.github.io/calculator")




  8. p.MustElementR("button", "1").MustClick()

  9. p.MustElementR("button", `^\+[b][size=3]获取图片[/size][/b]
  10. [size=3]  思路一样,区别是我们需要获取二进制的图片数据了,这里需要用到 Element 的MustResource方法:[/size]
  11. [code]<font size="3">// MustResource is similar to Element.Resource

  12. func (el *Element) MustResource() []byte {

  13. bin, err := el.Resource()

  14. el.e(err)

  15. return bin

  16. }




  17. // Resource returns the "src" content of current element. Such as the jpg of <img src="a.jpg">

  18. func (el *Element) Resource() ([]byte, error) {

  19. src, err := el.Evaluate(evalHelper(js.Resource).ByPromise())

  20. if err != nil {

  21. return nil, err

  22. }




  23. return el.page.GetResource(src.Value.String())

  24. }</font>
复制代码


这里会返回一个字节数组,需要我们进行转换。rod 的 util 包也提供了相关方法:


  1. <font size="3">// OutputFile auto creates file if not exists, it will try to detect the data type and

  2. // auto output binary, string or json

  3. func OutputFile(p string, data interface{}) error {

  4. dir := filepath.Dir(p)

  5. _ = Mkdir(dir)




  6. var bin []byte




  7. switch t := data.(type) {

  8. case []byte:

  9. bin = t

  10. case string:

  11. bin = []byte(t)

  12. case io.Reader:

  13. f, _ := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)

  14. _, err := io.Copy(f, t)

  15. return err

  16. default:

  17. bin = MustToJSONBytes(data)

  18. }




  19. return ioutil.WriteFile(p, bin, 0664)

  20. }</font>
复制代码


这里接收的 data 就可以是个字节数组,p 是文件输出路径。OutputFile 会自行处理创建目录,文件,写入数据的流程。下面我们改下代码看看:


  1. <font size="3">package main




  2. import (

  3.     "github.com/go-rod/rod"

  4.     "github.com/go-rod/rod/lib/utils"

  5. )




  6. func main() {

  7.     page := rod.New().MustConnect().MustPage("https://www.wikipedia.org/")




  8.     page.MustElement("#searchInput").MustInput("earth")

  9.     page.MustElement("#search-form > fieldset > button").MustClick()




  10.     el := page.MustElement("#mw-content-text > div.mw-parser-output > table.infobox > tbody > tr:nth-child(1) > td > a > img")

  11.     _ = utils.OutputFile("b.png", el.MustResource())

  12. }</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,填充以下内容:



  1. <font size="3">// This is the setup file for this test suite.




  2. package main




  3. import (

  4. "testing"




  5. "github.com/go-rod/rod"

  6. "github.com/ysmood/got"

  7. )




  8. // test context

  9. type G struct {

  10. got.G




  11. browser *rod.Browser

  12. }




  13. // setup for tests

  14. var setup = func() func(t *testing.T) G {

  15. browser := rod.New().MustConnect()




  16. return func(t *testing.T) G {

  17. t.Parallel() // run each test concurrently




  18. return G{got.New(t), browser}

  19. }

  20. }()




  21. // a helper function to create an incognito page

  22. func (g G) page(url string) *rod.Page {

  23. page := g.browser.MustIncognito().MustPage(url)

  24. g.Cleanup(page.MustClose)

  25. return page

  26. }</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 获取到指定元素,触发点击。



  1. <font size="3">// MustElementR is similar to Page.ElementR

  2. func (p *Page) MustElementR(selector, jsRegex string) *Element {

  3. el, err := p.ElementR(selector, jsRegex)

  4. p.e(err)

  5. return el

  6. }




  7. // ElementR retries until an element in the page that matches the css selector and it's text matches the jsRegex,

  8. // then returns the matched element.

  9. func (p *Page) ElementR(selector, jsRegex string) (*Element, error) {

  10. return p.ElementByJS(evalHelper(js.ElementR, selector, jsRegex))

  11. }</font>
复制代码


这里的 MustElementR 补充了正则能力,毕竟有些元素单独靠 selector 无法定位,这里是增强的能力。
  触发元素点击后,通过断言,判断文本和指定的结果是否匹配即可。
  第二个 case 也是类似的场景,大家可以由此体会一下 MustElementR 的用法。
  执行测试case和平常的 Golang 单测没有区别,直接 go test 命令即可。
  小结
  这里我们只是拿出来 rod 常见的一些用法,它可以打印,可以转图片,截屏,导出 pdf。可以模拟人为的浏览器操作,整体功能还是非常强大的,建议大家自己动手试一下。官方的 guide 也是很不错的参考资料。







欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2