更加健壮的自动化脚本—Python页面对象(二)

2014-11-10   出处: pragprog.com  作/译者:Adam Goucher/大头

魔法

从定义了类的用户名和密码属性的两行开始,事情开始变得真的很有趣。请注意,我们定义它们为非字符串或整数,而是作为描述符号(descriptor)对象。简单地说,一个描述符是有它的get,set和delete行为改写的对象。可改写是Python页面对象的魔力。


纵观UsernameElement类,我们看到,它也有一个自定义的构造函数,其目的是设置本地对象的locator。LoginPageObject.username的值被分配后就可以随时运行__set__功能,它不仅仅是存储该值,而是将其输入到页面的相应位置。由于UsernameElement有BasePageElement作为其超类,这个元素并没有什么特别之处,我们可以通过BasePageElement的get和delete来实现功能。
	from pageobjects import selenium_server_connection
 	    #
 	class BasePageElement(object):
 	    #
 	  def __get__(self, obj, cls=None):
 	    selenium_server_connection.get_text(self.locator)
 	    #
 	  def __delete__(self, obj):
 	    pass

在BasePageElement类中,在应用程序中最为突出的是运用所有字段的__get__。为此目的,我们假设本应用中大部分是文本字段。


警告:如果你要尝试对一个非文本字段的描述符进行get操作,你必须在特定元素类定义__get__行为。


正如set作为一个元素的行为是与浏览器进行交互并插入文本到页面中,get的行为就是从页面读取文本。


最后所需的一点来实施此模式的基础构造是将可能需要与服务器相连的对象与Selenium服务器的连接。最好首先通过使用目前定义的页面对象的PyUnit脚本来说明。

 	from pageobjects.login import LoginPageObject
 	from pageobjects import selenium_server_connection
 	    #
 	import sys, unittest, re, time, os.path, logging
 	    #
 	class PageObjectExample(unittest.TestCase):
 	    #
 	    def setUp(self):
 	        self.log = logging.getLogger("pragmatic.pageobjectexample")
 	        self.verificationErrors = []
 	        self.selenium =
 	          selenium_server_connection.connect("localhost", 4444, "*chrome",
 	          "http://some.test.site")
 	        self.selenium.start()
 	    #
 	    def testLogin(self)
 	        lpo = LoginPageObject(self.selenium)
 	        lpo.username = "adam@element34.ca"
 	        lpo.password = "password"
 	        lpo.submit()
 	    #
 	    def tearDown(self):
 	        self.selenium.stop()
 	        self.assertEqual([], self.verificationErrors)
 	    #
 	if __name__ == "__main__":
 	  unittest.main()

这是一个非常标准的 Selenium/pyunit的脚本,除了在访问Selenium服务器的过程中会创建一个单独的本地文件在包中。


为了实现这一点有两处代码,pageobjects以及__ init__.py:

 	from pageobjects.seleniumwrapper import SeleniumWrapper
 	    #
 	selenium_server_connection = SeleniumWrapper()

而在pageobjects/ seleniumwrapper.py,实际连接的建立被掩盖。

 	from selenium import selenium
 	    #
 	class SeleniumWrapper(object):
 	
 	    # singleton
 	    _instance = None
 	    #
 	    def __new__(cls, *args, **kwargs):
 	        if not cls._instance:
 	            cls._instance =
 	              super(SeleniumWrapper, cls).__new__(cls, *args, **kwargs)
 	        return cls._instance
 	    #
 	    def connect(self, host, port, browser, server):
 	        self.connection = selenium(host, port, browser, server)
 	        return self.connection

将这一切安排妥当后,让我们将所有的代码捆绑在一起并轻松地对这个脚本进行执行。


按步

  • Python解释器解析文件,检查语法错误,导入了一堆东西到工作区,并试着创建具有unittest.TestCase的作为超类的PageObjectExample类。
  • 这也决定了当程序开始执行时unittest.main()是应该先被执行的。
  • PyUnit框架扫描TestCase类的文件,找到他们后看他们是否有开头为“test.”的任何方法。
  • 由于PageObjectExample有TestLogIn,随后它就执行安装方法,做了一些事情,但最重要的是使用我们封装的Selenium服务器的连接来与运行的Selenium RC服务器进行通信。
  • 然后实际的测试方法被调用时,第一行代码创建了一个LoginPageObject,后续带来了创建UsernameElement和PasswordElement对象。
  • 接下来的两行触发了UsernameElement和PassswordElement对象的__set__方法进入页面来输入用户名和密码。
  • 该页面随后被提交。
  • 如果这是一个真正的脚本,会有一些断言,并到数据库中进行检查,以确保如预期一般运行。
  • 现在,测试手段完成,执行tearDown方法。
  • 最后,由于没有其他的方法有前缀“test”,结果被显示给用户。


页面对象肯定是在UI层面管理测试维护成本的一种渐露头角的方式,但有一个与之相关的重大的技术成本。对于刚开始编程的人们来说,我可能还是建议他们首先抽象成函数,而不是对象。但对于有了一定了解和认识的人来说,或者如果你在自动化不断发生颠覆性变化的应用程序,那么页面对象绝对是一个值得考虑的模式。

上篇: 更加健壮的自动化脚本—Python页面对象(一)

【英文原文:https://pragprog.com/magazines/2010-08/page-objects-in-python

{测试窝原创译文,译者:大头}

译者简介:大头,在读日本九州大学修士,计算机专业,主研究方向为文本挖掘,及自然语言处理。


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
380° /3804 人阅读/0 条评论 发表评论

登录 后发表评论