|
应用Selenium进行Web测试时,经常会遇到下面的几个麻烦问题:
大量使用name、id、xpath等页面元素。无论是功能修改、UI重构还是交互性改进都会影响到这些元
素,这使得Selenium测试变得非常脆弱。
过于细节的页面操作不容易体现出行为的意图,一段时间之后就很难真正把握测试原有的目的了,这
使得Selenium测试变得难于维护
对具体数据取值的存在依赖,当个别数据不再合法的时候,测试就会失败,但这样的失败并不能标识
功能的缺失,这使得Selenium测试变得脆弱且难以维护。
而这几点直接衍生的结果就是不断地添加新的测试,而极少地去重构、利用原有测试。其实这倒也是
正常,单元测试测试写多了,中国IT室验实也有会有这
样的问题。不过比较要命的是,Selenium的执行速度比较慢(相对单元测试),随着测试逐渐的增多,
运行时间会逐渐增加到不可忍受的程度。一组意图不明而且难以维护的Selenium测试,可以很轻松地在
每次构建(Build)的时候杀掉40分钟甚至2个小时的时间,我就有曾有花2个小时坐在电脑前面等待450
个 Selenium测试运行通过的悲惨经历。因此合理有效地规划Selenium测试就显得格外的迫切和重要了。
而目前比较行之有效的办法,往大了说,可以叫基于领域的Web测试(Domain Based Web Testing),具
体来讲,就是Page Object Pattern。
Page Object Pattern里有四个基本概念:Driver、Page、Navigator和Shortcut等。Driver是测试真
正的实现机制,比如 Selenium,比如Watir,比如HttpUnit。它们懂得如何去真正执行一个Web行为,通
常包含像Click、Select、Type等这样的表示具体行为的方法;Page是对一个具体页面的封装,它们了解
页面的结构,知道诸如id、name、class和xpath这类实现细节,并描述用户可以在其上进行何种操作;
Navigator则代表了URL,表示一些不经页面操作的直接跳转;最后Shortcut就是helper方法了,需要看
具体的需要而定。下面来看一个超级简单的例子——测试登录页面。
1. Page Object
假设我们使用一个单独的登录页面进行登录,那么可能会将登录的操作封装在一个名为LoginPage的
page object里:
class LoginPage
def initialize driver
@driver = driver
end
def login_as user
@driver.type 'id=', user[:name]
@driver.type 'xpath=', user[:password]
@driver.click 'name='
@driver.wait_for_page_to_load
end
end
login_as是一个具有业务含义的页面行为。在login_as方法中,page object负责通过依靠id、xpath
、name等信息完成登录操作。在测试中,我们可以这样来使用这个page object:
page = LoginPage.new $selenium
page.login_as :name => 'xxx', :password => 'xxx'
不过既然用了Ruby,总要用一些ruby sugar吧,我们定义一个on方法来表达页面操作的环境:
def on page_type, &block
page = page_type.new $selenium
page.instance_eval &block if block_given?
end
之后我们就可以使用page object的类名常量和block描述在某个特定页面上操作了:
on LoginPage do
login_as :name => 'xxx', :password => 'xxx'
end
除了行为方法之外,我们还需要在page object上定义一些获取页面信息的方法,比如获取登录页面
的欢迎词的方法:
def welcome_message
@driver.get_text 'xpath='
end
这样测试也可表达得更生动一些:
on LoginPage do
assert_equal 'Welcome!', welcome_message
login_as :name => 'xxx', :password => 'xxx'
end
当你把所有的页面都用Page Object封装了之后,就有效地分离了测试和页面结构的耦合。在测试中
,只需使用诸如login_as和add_product_to_cart这样的业务行为,而不必依靠像id、name等这些具体且
易变的页面元素了。当这些页面元素发生变化时,只需修改相应的page object就可以了,而原有测试基
本不需要太大或太多的改动。 |
|