【项目-自动化测试】PO模式

目录

driver.py:

BasePage.py:

function.py:

myunit.py:

AddPage.py:

LoginPage.py:

test_csv.csv:

test_add.py:

test_run.py:

PO模式左侧项目文件结构


driver.py:

  • 编写存放主流浏览器驱动的方法,返回值为浏览器的驱动  ​

 from selenium import webdriver 
'''
 存放驱动
 '''
 ​
 ​
 def my_Edge():
     driver = webdriver.Edge()
     return driver

BasePage.py:

  • 二次封装myselenium类

导入写好的driver方法

  1. 在类中初始化(init)驱动url(驱动为自己编写的driver方法返回的驱动,url为具体地址)

  2. 编写打开网址方法(my_get)

  3. 编写定位元素方法(my_find_element),传参一个列表(*代表数据类型为列表)

  4. 编写弹窗处理方法(my_alert),传参一个布尔值,ture时确定弹窗,flase时取消弹窗

'''封装selenium的基础操作类方法(get、find_element等)'''
 ​
 ​
 class basepage:
     def __init__(self, driver):
         self.url = 'http://192.168.5.10/pams/'
         self.driver = driver
 ​
     def my_get(self):
         self.driver.get(self.url)
 ​
     def my_find_element(self, *loc):
         return self.driver.find_element(*loc)
 ​
     def my_alert(self, istrue: bool):
         new_driver = self.driver.switch_to.alert()
         if istrue:
             new_driver.accept()
         else:
             new_driver.dissmiss()

function.py:

导入os(python与系统之间路径的相关操作)\time(后续用当前时间与截图文件名做拼接)\pyautogui(python内置的截图)\csv(数据读取)

  • 当页面有弹窗拦截时,我们无法通过驱动(driver.get_screenshort_as_file())进行截图,所以就用到pyautogui模块,该模块是跳过驱动,直接用后台截图的,可以捕捉到有弹窗的页面。需下载。

  • 测试过程中极可能会对某个模块进行多轮测试,模块名相同的情况下,不利于我们观察测试结果,所以我们可以利用time模块,获取当前时间,并于模块名进行拼接,形成较易区分的全新截图名称。

  • 为提高代码的复用性及准确性(避免因为路径问题而测试失败),我们可以利用os模块获取绝对路径

截图

  1. 新建截图方法,传参模块名称驱动当前页面是否有弹窗

  2. 获取当前时间(time.strftime('%Y-%m-%d-%H%M%S', time.localtime()))

  3. 拼接模块名称、时间和文件后缀名(.png),形成截图名称

  4. 利用os.path.dirname()层层获取根目录,再利用os.path.join()拼接存放截图的全路径

  5. 截图名称join到存放截图的全路径,调用get_screenshot_as_file(),并传入全新路径

数据读取

  • 可加入是否忽略首行选项

 import os
 import csv
 import time
 ​
 '''
 截图、数据驱动读取、获取弹窗文本等方法
 '''
 ​
 ​
 def my_csv(filename, isIgonre: bool):
     '''
     读取文件内容,生成列表
     :param path: 数据文件路径
     :param isIgonre: 是否忽略首行
     :return: 返回值为全新列表
     '''
     # 获取当前文件的根目录,__file__ 当前文件
     model = os.path.dirname(__file__)
     test_case = os.path.dirname(model)
     web_site = os.path.dirname(test_case)
     # 将传入的文件名与存放该文件的根目录进行拼接,生成该文件的全路径
     new_path = os.path.join(web_site, 'test_data', filename)
     with open(new_path, mode='r', encoding='utf-8') as f1:
         f1_data = csv.reader(f1)
         result_list = []
         index = 0
         for i in f1_data:
             if isIgonre:
                 if index != 0:
                     result_list.append(i)
             else:
                 result_list.append(i)
             index += 1
     return result_list
 ​
 ​
 def my_screenshot(driver, photo_name):
     '''
     截图方法
     :param driver: 驱动
     :param photo_name:截图名称
     :return: 无
     '''
     # 拼接时间,localtime()获取当前时间戳
     filetime = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
     file_name = photo_name + '|' + filetime + '.png'
     # 再获取路径、拼接路径,生成截图的存放路径
     modle_path = os.path.dirname(__file__)
     test_case_path = os.path.dirname(modle_path)
     web_site_path = os.path.dirname(test_case_path)
     all_file_path = os.path.join(web_site_path, "test_report", r"screenshot", file_name)
     print(all_file_path)
     driver.get_screenshot_as_file(all_file_path)
 ​
 ​
 def get_alert_text(driver):
     # 获取弹窗文本
     real_text = driver.switch_to.alert.text
     return real_text
 ​

myunit.py:

  1. 导入driver文件夹中的driver.py 和 unittest

  2. 封装一个继承自unittest.TestCase的类

  3. 编写setUp()方法,调用自己编写的浏览器驱动,初始化实际参与测试的驱动,增加智能等待和窗口最大化

  4. 编写tearDown()方法,关闭浏览器

 import time
 import unittest
 ​
 from driver.driver import my_Edge
 '''二次封装unittest框架中的Setup(添加5秒的智能等待和浏览器窗口最大化)和tearDown(退出浏览器)等方法'''
 ​
 ​
 class my_unit(unittest.TestCase):
     def setUp(self) -> None:
         self.driver = my_Edge()
         self.driver.implicitly_wait(5)
         self.driver.maximize_window()
 ​
     def tearDown(self) -> None:
         time.sleep(1)
         self.driver.quit()

AddPage.py:

  • 封装继承自myselenium的类]

步骤

导入By和BasePage

  1. 定义类中的公共变量(该变量为页面上的元素及其定位方法),变量数据类型为元组,例:(By.ID,"")

  2. 定义定位元素及对元素的操作(输入、点击、清空等)方法,需传参输入的值(无输入即无参数),注意:因传参数据类型为元组,所以需在调用公共变量之前加入解包符号 *

add_action方法:

  • 参数为:AddPage类型的实例化对象,品牌名称,品牌编码

  • 方法具体内容:将AddPage类中封装的每一步操作连贯起来,使其成为一个完整的行为,即:通过该对象按照实际操作流程调用类中的每一个方法  ​

 from selenium.webdriver.common.by import By
 ​
 from Website.test_case.page_object.BasePage import basepage
 ​
 '''引入BasePage.py中封装好的方法,引入By方法类,
 封装好商品品牌添加页面元素(使用LINK_TEXT方法封装商品品牌按钮,
 使用XPATH方法封装新增按钮,
 使用XPATH方法封装商品品牌名称输入框,
 使用CSS方法封装保存按钮,
 封装点击商品品牌按钮、点击新增按钮、输入商品品牌名称、点击保存按钮等操作),
 封装添加成功以及添加失败的提示信息文字'''
 ​
 ​
 class add_page(basepage):
     brand_btn_text = (By.LINK_TEXT, '品牌')
     brand_new_xpath = (By.XPATH, '//*[@id="content"]/div[2]/div/div[1]/button')
     brand_name_xpath = (By.XPATH, '//*[@id="title"]')
     brand_code_xpath = (By.XPATH, '//*[@id="code"]')
     brand_save_css = (By.CSS_SELECTOR, '.btn.blue.margin-right-10')
 ​
     def brand_click(self):
         self.my_find_element(*self.brand_btn_text).click()
 ​
     def brand_new(self):
         self.my_find_element(*self.brand_new_xpath).click()
 ​
     def brand_name_input(self, brand_name):
         self.my_find_element(*self.brand_name_xpath).send_keys(brand_name)
 ​
     def brand_code(self, code):
         self.my_find_element(*self.brand_code_xpath).send_keys(code)
 ​
     def brand_save(self):
         self.my_find_element(*self.brand_save_css).click()
 ​
 def add_action(brand:add_page,brand_name, brand_code):
     brand.brand_click()
     brand.brand_new()
     brand.brand_name_input(brand_name)
     brand.brand_code(brand_code)
     brand.brand_save()  

LoginPage.py:

  • 同理与AddPage.py

 
 from time import sleep
 from selenium.webdriver.common.by import By
 ​
 from Website.test_case.page_object.BasePage import basepage
 ​
 from driver.driver import my_Edge
 from Website.test_case.model.function import my_csv
 ​
 '''引入BasePage.py中封装好的方法,
 引入By方法类,封装登录用例页面元素位置和操作
 (使用ID方法封装用户名输入框,
 使用NAME方法封装密码输入框、
 使用CLASS方法封装登录按钮位置,
 封装输入用户名、密码、点击登录按钮等操作)'''
 ​
 ​
 class Login_page(basepage):
     username_id = (By.ID, 'loginName')
     password_name = (By.NAME, 'password')
     login_btn_class = (By.CLASS_NAME, 'blue-button')
 ​
     def username_input(self, username):
         self.my_find_element(*self.username_id).send_keys(username)
 ​
     def password_input(self, password):
         self.my_find_element(*self.password_name).send_keys(password)
 ​
     def login_btn_click(self):
         self.my_find_element(*self.login_btn_class).click()
 ​
 ​
 def login_action(login_ac: Login_page, username, password):
     login_ac.my_get()
     sleep(0.5)
     login_ac.username_input(username)
     login_ac.password_input(password)
     sleep(0.5)
     login_ac.login_btn_click()
 ​
 ​
 if __name__ == '__main__':
     login_ac = Login_page(my_Edge())
     login_list = my_csv('login.csv', False)
     print(login_list)
     login_action(login_ac, login_list[0][0], login_list[0][1])

【注意】:在PO模式中调用二次封装的selenium中的find_element()方法时,需要在传的元组参数前加解包符号 *

test_csv.csv:

  • 数据文件,存放测试过程中会用到的测试数据,如用户名、密码、断言所用到的预期提示文本等

  • 数据与数据之间使用英文逗号间隔,同组数据存放在同一行

  •  student,student,测试数据,,请填写品牌编码!
     student,student,123,,品牌名称只能包含中文字符!
     student,student,,,请填写品牌名称!
     student,student,测试数据,,请填写品牌编码!
     student,student,测,,请填写品牌编码!

test_add.py:

  • 整合LoginPage中的登录行为和AddPage中的添加品牌行为,使它们成为一个具体的测试行为

  • 业务流程:登录-->添加品牌-->断言页面返回的提示信息

步骤

导包:ddt / 自定义的function、myunit、loginpage、basepage、addpage

  • ddt有两种导包形式

    • import ddt

    • from ddt import ddt,data,unpack

    • 使用第二种形式,后续装饰器可直接写@ddt/data/unpack

  1. 封装一个被@ddt.ddt装饰的类,该类继承自二次封装的myunit

  2. 在使用数据驱动的测试用例方法前使用@ddt.data()指明数据来源。

    1. 参数为:调用function中编写的csv数据读取方法,返回的全新数据列表。注:调用该方法需在前加列表标识符 *

  3. 在@ddt.ddt()方法后,换行使用@ddt.unpack解包

  4. 编写test开头的使用数据驱动的方法(测试用例),该方法须接收与数据文件内相同个数的参数,即数据文件有3个参数,该测试方法须有三个与之一一对应的参数

  5. 在测试方法内,创建LoginPage类和AddPage类的实例化对象,调用LoginPage.py中的登录行为的方法,传参该类的对象及解包后的参数,AddPage类同理。

  6. 进行断言

 import ddt
 ​
 from Website.test_case.model.function import *
 from Website.test_case.model.myunit import my_unit
 from page_object.LoginPage import *
 from page_object.AddPage import *
 ​
 '''引入unittest、ddt以及之前封装好的model,LoginPage,AddPage中的方法类,
 根据用例编写6条测试用例脚本,创建data参数来接收测试数据,
 并使用数据驱动输入用户名和密码(XTGLY/123456),
 使用数据驱动输入商品品牌名称,然后进行截图操作,
 最后对每一条测试用例进行assertIn断言操作,对比提示信息是否和预期一致;'''
 ​
 ​
 @ddt.ddt
 class add(my_unit):
     @ddt.data(*my_csv('test_csv.csv', False))
     @ddt.unpack
     def test_add_brand(self, username, password, name, code, expect_text):
         login = Login_page(self.driver)
         brand = add_page(self.driver)
 ​
         login_action(login, username, password)
         add_action(brand, name, code)
         self.assertIn(get_alert_text(self.driver), expect_text, '断言失败')

test_run.py:

  • 执行测试文件,运行指定开头和格式的文件,并在指定位置生成报告(.html文件)

导包:os / unittest / HTMLTestRunner

  1. 创建测试集合

  2. 创建测试加载器

  3. 将指定路径下的指定格式的文件添加到测试集合

  4. 生成测试报告的指定存放路径

  5. 将结果写入测试报告

  6. 运行该测试集合

 import os
 import unittest
 ​
 from HTMLTestRunner import HTMLTestRunner
 ​
 suit = unittest.TestSuite()
 loader = unittest.TestLoader()
 suit.addTest(loader.discover('./test_case/', 'test*.py'))
 ​
 path = os.path.join('./test_report/', 'test.html')
 with open(path, mode='wb') as f1:
     runner = HTMLTestRunner(f1, title='资产管理系统', description='添加品牌')
     runner.run(suit)

PO模式左侧项目文件结构

  • 19
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值