Selenium - Page Object 设计模式

前几章陆续介绍了Selenium API提供的各种操作网页元素的方法。作为一个在实际工作中所搭建自动化测试框架中,这仅仅是非常小的一部分。在实践中除了网页元素操作之外还需考虑得更多,诸如测试用例的组织, 测试报告,自动化测试的触发条件等等。所以在接下来的几篇中会陆续介绍如何搭建一个完整的测试框架所设计的一些工具。

今天先来介绍一下编写自动化测试用例时所使用的一种设计模式 Page Object. 这里先看一个例子。

class loginTest(myunit.MyTest):
    
    def test_login_successfully(self):
        login_button = self.driver.find_element_by_id('login_btn')
        username_textbox = self.driver.find_element_by_id('username_input')
        password_textbutton = self.driver.find_element_by_id('pwd_input')
        username_textbox.send_keys('correct user')
        password_textbutton.send_keys('correct password')
        login_button.click()
        
    def test_login_failure(self):
        login_button = self.driver.find_element_by_id('login_btn')
        username_textbox = self.driver.find_element_by_id('username_input')
        password_textbutton = self.driver.find_element_by_id('pwd_input')
        username_textbox.send_keys('wrong user')
        password_textbutton.send_keys('correct password')
        login_button.click()

这是在我还没有运用page object的时候写的两条测试用例,一个登录成功,一个登录失败。 这里可以看到页面元素的操作和测试代码是混合在一起的。这里很明显的三个问题,第一两条测试用例大量代码重复;第二大量与测试逻辑无关的代码造成用例易读性的降低;第三一旦UI发生变化需要修改每一条测试用例,维护成本高昂。

Page Object的设计模式很好地解决了以上问题,它遵循一个原则既页面操作和测试场景分开。每一个页面看做一个类,里面的公共方法既是这个网页提供的与用户交互的功能。当然如果有比较复杂的UI元素,则这些元素可以是单独的类。但是最后暴露给测试代码的交互方法仍然是page类来提供。Page类中没有任何测试代码,没有任何的断言(assertion)。对于测试代码而言无需关心内部的实现,只需调用对应的公共方法提供的交互功能,无须自己实现任何网页元素的操作,还是举个例子。

class Login(Page):
    '''user login'''
    url = '/UserManage/Login'

    __login_username_loc = (By.ID, "txtUInfo")
    __login_password_loc = (By.ID, "txtpwd")
    __login_button_loc = (By.LINK_TEXT,"登   录")

    #input username
    __def login_username(self, username):
        self.find_element(*self.login_username_loc).send_keys(username)

    #input_password
    __def login_password(self, password):
        self.find_element(*self.login_password_loc).send_keys(password)

    #click login button
    __def login_button(self):
        self.find_element(*self.login_button_loc).click()
    #login
    def user_login(self, username="defaultuser", password="defaultpwd"):
        self.open()
        self.login_username(username)
        self.login_password(password)
        self.login_button()

    __error_hint_loc = (By.ID, "sperrtip")
    __login_success_loc = (By.ID, "ausername")

    #login error message
    def error_hint(self):
        return self.find_element(*self.error_hint_loc).text

    #login successfully
    def user_login_success(self):
        return self.find_element(*self.login_success_loc).text
class loginTest(myunit.MyTest):
    
    def test_login1(self):
        page = Login(self.driver)
        page.user_login()
        self.assertEquals(page.user_login_success(), 'defaultuser')

    def test_login2(self):
        '''The test case will be failed'''
        page = Login(self.driver)
        page.user_login()
        self.assertEquals(page.user_login_success(), 'wronguser')

    def test_login_3(self):
        '''wrong pwd'''
        page = Login(self.driver)
        page.user_login('userb','111111')
        self.assertEquals(page.error_hint(), '密码错误,请重新输入密码'.decode('utf8'))
第一部分是一个login page类,里面所有的定位操作都是私有的,只对外开放了login page支持的几种交互方式用户登录,成功登录信息,登录失败信息。第二部分则是我们的测试代码,测试了三种不同的场景。由此可见无论我UI如何变化,都会对所有的测试代码都是不影响的,反之亦然。当然这个例子还是有改进空间的,例如将测试数据与测试代码再分离,进一步提高测试代码的可读性和复用性,降低维护成本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值