伪原创网站源码( 如何面对UI变化时,测试用例也要跟着变化?(组图))

优采云 发布时间: 2022-03-15 21:01

  伪原创网站源码(

如何面对UI变化时,测试用例也要跟着变化?(组图))

  

  PageObjects 简介

  在为 UI 页面(如网页、移动页面)编写测试用例时,测试用例中有很多元素和操作细节。UI变化时如何面对测试用例变化的问题?PageObject 设计模式首次亮相(由 IT 大亨 Martin Flower 提出)。

  在使用 UI 自动化测试工具(Selenium、Appium 等)时,如果没有统一的规范模式,随着用例数量的增加会变得难以维护,但 PageObject 保持自动化脚本有序,单独维护页面和封装了细节,并且可以使测试用例更加健壮而无需进行重大更改。

  页面对象使用

  具体方法:将元素信息和操作细节封装到Page类中,在测试用例上调用Page对象(PageObject)。例如,如果有一个函数“选择专辑标题”,则需要为其创建一个函数 selectAblumWithTitle()。操作细节在函数内部。findElementsWithClass('album') 等:

  

  以选择“获取专辑标题”为例,伪代码如下:

  selectAblumWithTitle() {

#选取相册

findElementsWithClass('album')

#选取相册标题

findElementsWithClass('title-field')

#返回标题内容

return getText()

}

  PageObject的主要原理是提供一个简单的接口(或函数,如上面的selectAblumWithTitle),让调用者可以对页面做任何操作,点击页面元素,在输入框中输入内容等。因此,如果您想访问文本字段,页面对象应该具有获取和返回字符串的方法。页面对象应该封装对数据的操作细节,例如查找元素和点击元素。当一个页面元素改变时,你应该只改变Page类中的内容,而不是调用它的地方。

  不要为每个 UI 页面创建页面类,而应该只为页面中重要的元素创建页面类。例如,如果一个页面显示了多个专辑,则应该创建一个专辑列表页面对象,其中收录许多专辑页面对象。如果某些复杂的 UI 层次结构仅用于组织 UI,那么它不应该出现在页面对象中。页面对象的目的是通过对页面进行建模来使应用程序的用户有意义:

  

  如果要导航到另一个页面,初始页面对象应该返回另一个页面对象,例如点击注册进入注册页面,你应该在代码中返回Register()。如果要获取页面信息,可以返回基本类型(字符串、日期)。

  建议不要在页面对象中放置断言。应该测试页面对象,而不是让页面对象自己测试。页面对象的职责是提供有关页面状态的信息。Page Object 在这里只用 HTML 描述,这种模式也可以用来隐藏 Java swing UI 细节,它可以与所有 UI 框架一起使用。

  PageObject的六大原则

  Selenium 为 PageObject 的核心思想浓缩了六大原则。只有掌握了六大原则的精髓,才能进行PageObject的最佳实践练习:

  public 方法表示页面提供的服务。不要暴露页面详细信息。不要混合断言和操作细节。该方法可以返回新打开的页面。不要将整个页面内容放在 PO 中。同样的行为会产生不同的结果,可以封装不同的结果

  下面,对以上六项原则进行更详细的实战解释:

  原则一:将功能(或服务)封装在页面中,例如点击页面中的一个元素,可以进入一个新页面,那么可以为此服务封装“进入新页面”方法。原则二:封装细节,只对外提供方法名(或接口)。原则 3:不要在封装的操作细节中使用断言,将断言放在单独的模块中,例如测试用例。原理四:点击一个按钮会打开一个新页面,可以使用return方法表示跳转,例如return MainPage()表示跳转到新的PO:MainPage。原则五:只为页面中的重要元素设计PO,不重要的内容丢弃。原则 6:一个动作可能产生不同的结果。例如,点击一个按钮后,点击可能会成功,也可能会失败。两个结果分别封装了两个方法,click_success和click_error。基于企业微信的PO实际案例

  以企业微信首页为例。企业微信首页主要有即时注册和企业登录两大功能。

  企业微信网址:

  

  点击企业登录,进入登录页面,扫码登录并注册为企业。

  

  点击企业注册,进入注册页面,输入相关信息进行注册。

  

  使用Page Object原理对页面进行建模,涉及到三个页面:首页、登录、注册。在代码中创建对应的三个类Inde、Login、Register:

  不管登录页面有多少元素,隐藏内部界面控件,登录成功和失败会分别返回不同的页面。通过方法返回值判断登录是否符合预期的UML图。

  

  实际代码

  目录结构

  

  BasePage 是所有页面对象的父类。它为子类提供公共方法。例如,下面的 BasePage 提供了初始化驱动和退出驱动。代码中,在base_page模块的BasePage类中使用了__init__initial方法来初始化操作,包括驱动的多路复用、驱动的赋值、全局等待(隐式等待)的设置等:

  from time import sleep

from selenium import webdriver

from selenium.webdriver.remote.webdriver import WebDriver

class BasePage:

def __init__(self, driver: WebDriver = None):

#此处对driver进行复用,如果不存在driver,就构造一个新的

if driver is None:

# Index页面需要用,首次使用时构造新driver

self._driver = webdriver.Chrome()

# 设置隐式等待时间

self._driver.implicitly_wait(3)

# 访问网页

self._driver.get(self._base_url)

else:

# Login与Register等页面需要用这个方法,避免重复构造driver

self._driver = driver

def close(self):

sleep(20)

self._driver.quit()

  Index是企业微信首页的页面对象。它有两种方法,一种是进入注册页面对象,另一种是进入登录页面对象。这里return方法返回page对象实现页面跳转,例如:goto_register方法返回Register实现从首页到Registration页面的跳转:

  from selenium.webdriver.common.by import By

from test_selenium.page.base_page import BasePage

from test_selenium.page.login import Login

from test_selenium.page.register import Register

class Index(BasePage):

_base_url = "https://work.weixin.qq.com/"

# 进入注册页面

def goto_register(self):

self._driver.find_element(By.LINK_TEXT, "立即注册").click()

# 创建Register实例后,可调用Register中的方法

return Register(self._driver)

# 进入登录页面

def goto_login(self):

self._driver.find_element(By.LINK_TEXT, "企业登录").click()

# 创建Login实例后,可调用Login中的方法

return Login(self._driver)

  login是登录页面的页面对象。主要功能有:进入注册页面,扫描二维码。因此,创建了两个方法来表示两个函数:scan_qrcode 和 goto_registry。代码与上面类似,但更多介绍:

  from selenium.webdriver.common.by import By

from test_selenium.page.base_page import BasePage

from test_selenium.page.register import Register

class Login(BasePage):

# 扫描二维码

def scan_qrcode(self):

pass

# 进入注册页面

def goto_registry(self):

self._driver.find_element(By.LINK_TEXT, "企业注册").click()

return Register(self._driver)

  Register是注册页面的page对象。主要功能是填写正确的注册信息。填写错误信息时,返回错误信息。register 方法实现了正确的表单填写并在完成时返回自身(页面仍然停留在注册页面上)。get_error_message 方法实现错误填充。如果填写错误,则采集错误内容并返回:

  from selenium.webdriver.common.by import By

from test_selenium.page.base_page import BasePage

class Register(BasePage):

# 填写注册信息,此处只填写了部分信息,并没有填写完全

def register(self, corpname):

# 进行表格填写

self._driver.find_element(By.ID, "corp_name").send_keys(corpname)

self._driver.find_element(By.ID, "submit_btn").click()

# 填写完毕,停留在注册页,可继续调用Register内的方法

return self

#填写错误时,返回错误信息

def get_error_message(self):

# 收集错误信息并返回

result=[]

for element in self._driver.find_elements(By.CSS_SELECTOR, ".js_error_msg"):

result.append(element.text)

return result

  test_index 模块是对上述功能的测试。它独立于页面类。在TestIndex类中,只需要调用页面类提供的方法即可。例如下面注册页面和登录页面的测试使用了test_register和test_login方法:

  from test_selenium.page.index import Index

class TestIndex:

# 所有步骤前的初始化

def setup(self):

self.index = Index()

# 对注册功能的测试

def test_register(self):

# 进入index,然后进入注册页填写信息

self.index.goto_register().register("霍格沃兹测试学院")

# 对login功能的测试

def test_login(self):

# 从首页进入到注册页

register_page = self.index.goto_login().goto_registry()\

.register("测吧(北京)科技*敏*感*词*")

# 对填写结果进行断言,是否填写成功或者填写失败

assert "请选择" in "|".join(register_page.get_error_message())

# 关闭driver

def teardown(self):

self.index.close()

  以上,欢迎留言讨论。更高级的自动化测试实践,建议学习霍格沃茨测试学院出品的《高级测试开发实践》课程。

  单击此处获取更多信息和视频

  :///t/topic/3595

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线