zoukankan      html  css  js  c++  java
  • Web自动化测试模式page object的小利器:gizmo

    0.问题

      今天看到公司的同事们在讨论page object的相关知识(也就是面向Web项目的自动化测试中的一种实现形式),刚好前一阵子研究了一下我们项目组使用的page object相关内容,所以在这里写篇入门级别的文章,跟大家介绍一下gizmo这个小工具。

    (大家可以先通过这篇文章看看page object的概念 http://www.infoq.com/cn/articles/domain-web-testing)

      说起来我研究gizmo也是有一段故事的,那天在工作时突然发现项目中一段代码是这样的

    on_page_with(:mega_menu) do |mega_menu|
    mega_menu.should have_single_word_space_caption(spaces.hashes)
    end

      其中调用了 have_single_word_space_caption这个方法,但是我却发现方法是这样定义的

    def has_single_word_space_caption? spaces
    ...
    end

      这不是很奇怪么,定义的时候明明是'has',调用时候却使用'have'...,于是我又找了找,发现了更奇怪的方法调用

    on_page_with(:mega_menu) do |mega_menu|
    mega_menu.should have_space_title(space_name)
    end

    def has_space_title? space_name
    end



      这个更离谱,have变has不说,连方法名最后的问号都没有了。自己想了半天都没想通,又问了问别人,也没有得到让我满意的答案,哎,没办法,只能踏上寻宝之路了。这段代码是我们利用gizmo,一个Ruby gem,来完成的page object模型,也就是说我们利用gizmo对我们项目中出现的网页都建立了模型,并且给这些网页模型中加入了相关方法。想找到为什么have变has,那么就先来google gizmo吧。(我会默认你接触cucumber测试,rspec,capybara等,就算你没有,我想理解下面的问题也不会很难的。)

    1.gizmo简介

      gizmo(https://github.com/icaruswings/gizmo)一个page object testing framework,秉承ruby中那种简单随意的风格,利用它,你很快就可以建立起一套合适的page object来。


    2.gizmo module

      首先介绍的就是gizmo module ,gizmo认为一个module就是在网页上面能独立出现的一块元素,比如淘宝最上方永远都出现的登陆窗口,或者是最下面的联系我们等。我个人认为,一个页面总是可以分解成不同的module。

      简单来说,gizmo的module需要满足以下条件:

    • module名字必须以PageWith开头,如下面的PageWithGithubSearch,module的文件名必须是page_with开头,如page_with_github_search.rb
    • 必须 include Gizmo::PageMixin
    # I'm gizmo module
    module PageWithGithubSearch
    include Gizmo::PageMixin
    end

     

      对于一个module来说,我个人建议最好不要将module当成是一个页面。因为某些网页中可能存在相同的块,比如我上面提到的淘宝的例子,如果我们将相同的内容抽成module,就像抽取方法一样,项目中就不会有重复的代码啦~~

    3.gizmo method

      有了module,我们该定义怎样的方法来满足我们的使用呢?总体来说,我们一般会用到四类方法

    • 判断页面是否加载正常
    • 与网页有所交互,比如点击按钮,输入文字等
    • 判断页面某元素是否存在或者不存在
    • 读取网页上面的信息
    module PageWithGithubSearch

    include Gizmo::PageMixin

    def valid?
    has_selector?("form[action='/search']")
    end

    def link_with_text(value)
    find("a", :text => value)
    end

    def have_content(value)
    has_content?(value)
    end

    define_action :click_element do |element|
    locate(element).click
    end
    end

      

      上述代码中,valid?方法就是判断页面是否加载正确(准确的说是页面中的某一个独立的块是否加载正确),你可以直接使用capybara的方法来帮助你判断加载是否成功(capybara, https://github.com/jnicklas/capybara)。如果某些情况你不需要验证是否加载正确,那么就不需要valid?方法,gizmo默认的valid?方法会永远返回true。

      define_action能帮助我们定义与页面上进行交互的方法,后面的:click_element是方法名,block中的参数是方法的参数。实现依然是capybara的代码,虽然在定义时我们使用了define_action(gizmo自已的dsl),但实际上运行时它还是会定义一个方法,之所以引入define_action的概念,个人觉得是可以非常方便的区分每个方法的职责,如果你需要与界面交互的方法,那就用define_action吧。

      link_with_text方法帮我们读取页面中的text值是value的a标签并且返回该标签,实际上find方法还是capybara的方法。

      have_content方法能判断该页面中是否包含某段文字。

      通过上面的介绍,我们就可以用valid?,define_action,def 这三种形式完成对module行为的定义。而在实现时,使用capybara来完成具体的操作(上述例子比较粗糙,希望大家在实际中能更多的参考capybara文档)。有人问我能否全部用def,不用define_action来定义方法,我觉得从功能来说完全可以,但是既然使用gizmo,那么就老老实实遵守规定吧。

    4.gizom call 

      总算定义完module了,那么我们该怎么用呢?其实很简单,直接上代码:

    on_page_with :github_search do |page|
    page.perform :search, query
    end

    on_page_with :github_search do |page|
    page.should have_content("github")
    end

      所有使用gizmo的时候都需要on_page_with方法,第一个例子中后面传入的:github_search是module的名字,注意需要去掉前面的PageWith并且全部小写,单词之间需要下划线,还要在前面加上冒号,比如PageWithGithubSearch就是:github_search。后面是你需要操作的block,如果我们需要调用define_action定义的方法,需要使用perform方法,然后传入的:search是方法名,后面跟方法的参数query.

      在第二个例子中,我们使用rspec中的should来判断 have_content("github")的返回值,也就是判断页面上是否包含github字符串。(不知你发现了没有,我定义的时候是方法名是has开头,调用时使用have并且去掉了'?')

      简单来说,on_page_with后面跟的就是使用module的名字,如果我们需要操作页面,就是用perform方法,如果需要进行某些判断,则使用rspec来完成。

    5.configuration

      对于使用者来说,最麻烦的就是配置问题了。我在gizmo主页上也没有找到很详细的配置文档,所以就给大家分享一下我的配置内容吧。

    #features/support/env.rb
    require 'capybara'
    require 'capybara/dsl'
    require 'capybara/cucumber'
    require 'gizmo'

    Capybara.default_driver = :selenium
    Capybara.default_wait_time = 10
    Capybara.default_selector= :css
    Capybara::Selenium::Driver::DEFAULT_OPTIONS[:resynchronize] = false
    Capybara.ignore_hidden_elements = false


    World(Capybara)
    World(Gizmo::Helpers)

    Gizmo.configure do |config|
    config.mixin_dir = File.dirname(__FILE__) + '../page_object'
    end

      值得说明的最后一部分,设置Gizmo.configure中设置的是存放gizmo module的文件夹,他是相对于env的路径,也就是说我可以把放gizmo module的文件夹叫做pages,并且把相关的module放在一个子文件夹下面进行管理。比如下面这种组织形式  

    page_object/
    ├── home_page
    │ ├── page_with_login.rb
    │ └── page_with_search.rb
    └── setting_page
    ├── page_with_password.rb
    └── page_with_photo.rb

      最后,你需要参照 https://github.com/icaruswings/gizmo/wiki/Capybara,给你的capybara打上补丁才能工作。

      那么,如果你有什么问题,可以给我留言,不过我建议你最好仔细看一看gizmo主页上面的介绍。那么,还等什么,开始page object之旅吧。

    ps:到现在为止,我依然没有确定have和has这个问题的答案,如果你知道,请你告诉我,谢谢。  

  • 相关阅读:
    Codeforces Round 546 (Div. 2)
    Codeforces Round 545 (Div. 2)
    Codeforces Round 544(Div. 3)
    牛客小白月赛12
    Codeforces Round 261(Div. 2)
    Codeforces Round 260(Div. 2)
    Codeforces Round 259(Div. 2)
    Codeforces Round 258(Div. 2)
    Codeforces Round 257 (Div. 2)
    《A First Course in Probability》-chaper5-连续型随机变量-随机变量函数的分布
  • 原文地址:https://www.cnblogs.com/iammatthew/p/2359298.html
Copyright © 2011-2022 走看看