V1顺序型:不能批量运行
import unittest
from selenium import webdriver
from time import sleep
driver = webdriver.Edge()# driver.maximize_window()
driver.implicitly_wait(30)
# driver.get(r"https://demo5.tp-shop.cn/")
# driver.find_element_by_partial_link_text("登录").click()driver.get("https://demo5.tp-shop.cn/Home/user/login.html")driver.find_element_by_css_selector("#username").send_keys("15217578333")driver.find_element_by_css_selector("#password").send_keys("123456")driver.find_element_by_css_selector("#verify_code").send_keys("AUWR")
driver.find_element_by_css_selector(".J-login-submit").click()
msg = driver.find_element_by_css_selector(".layui-layer-content").text
print(msg)
assert "账号不存在" == msg
driver.find_element_by_css_selector(".layui-layer-btn0").click()
sleep(2)
driver.quit()
assert "密码不存在" == msg
driver.find_element_by_css_selector(".layui-layer-btn0").click()
sleep(2)
driver.quit()
Unittest:代码冗余 业务脚本与页面对象没有分开
import unittest
from selenium import webdriver
from time import sleepclass TestLogin(unittest.TestCase):driver = Nonedef tearDown(self):self.driver.refresh()@classmethoddef setUpClass(cls):cls.driver = webdriver.Edge()# driver.maximize_window()cls.driver.implicitly_wait(30)# cls.driver.get(r"https://demo5.tp-shop.cn/")# cls.driver.find_element_by_partial_link_text("登录").click()cls.driver.get(r"https://demo5.tp-shop.cn/Home/user/login.html")@classmethoddef tearDownClass(cls):sleep(2)cls.driver.quit()def test_login_username_not_exist(self):driver = self.driverdriver.find_element_by_css_selector("#username").send_keys("15217578333")driver.find_element_by_css_selector("#password").send_keys("123456")driver.find_element_by_css_selector("#verify_code").send_keys("AUWR")driver.find_element_by_css_selector(".J-login-submit").click()msg = driver.find_element_by_css_selector(".layui-layer-content").textprint(msg)try:self.assertEqual("用户不存在", msg)driver.find_element_by_css_selector(".layui-layer-btn0").click()except AssertionError:self.driver.get_screenshot_as_file("../image/not_exist.png")# raisedef test_login_password_err(self):driver = self.driverdriver.find_element_by_css_selector("#username").send_keys("15217578333")driver.find_element_by_css_selector("#password").send_keys("123456")driver.find_element_by_css_selector("#verify_code").send_keys("AUWR")driver.find_element_by_css_selector(".J-login-submit").click()msg = driver.find_element_by_css_selector(".layui-layer-content").textprint(msg)try:self.assertEqual("密码错误",msg)driver.find_element_by_css_selector(".layui-layer-btn0").click()except AssertionError:self.driver.get_screenshot_as_file("../image/error.png")# raise
V3 PO page object 冗余代码 耦合性太强
#pagefrom selenium import webdriverclass PageLogin:def __init__(self):self.driver = webdriver.Edge()# driver.maximize_window()self.driver.implicitly_wait(30)# driver.get(r"https://demo5.tp-shop.cn/")# driver.find_element_by_partial_link_text("登录").click()self.driver.get(r"https://demo5.tp-shop.cn/Home/user/login.html")# 点击登录def page_click_login_link(self):pass# 输入用户名def page_input_username(self,username):self.driver.find_element_by_css_selector("#username").send_keys(username)# 输入密码def page_input_pwd(self,password):self.driver.find_element_by_css_selector("#password").send_keys(password)# 输入验证码def page_input_vertify_code(self,code):self.driver.find_element_by_css_selector("#verify_code").send_keys(code)# 点击登录def page_click_login_btn(self):self.driver.find_element_by_css_selector(".J-login-submit").click()# 获取异常提示信息def page_get_text(self):return self.driver.find_element_by_css_selector(".layui-layer-content").text# 点击提示框确认按钮def page_click_err_btn_ok(self):self.driver.find_element_by_css_selector(".layui-layer-btn0").click()# 组装业务登录方法、给业务层调用def page_login(self,username,password,code):self.page_click_login_link()self.page_input_username(username)self.page_input_pwd(password)self.page_input_vertify_code(code)self.page_click_login_btn()
#业务层
import unittest
from v3.page.page_login import PageLogin
from parameterized import parameterized
from time import sleep
class TestLogin(unittest.TestCase):def setUp(self):# 获取登录页面对象self.login = PageLogin()def tearDown(self):self.login.driver.quit()@parameterized.expand([("13822223333","123456","8888","账号不存在"),("13822223333","1236","8888","密码错误")])def test_login(self,username,password,code,expect):self.login.page_login(username,password,code)msg = self.login.page_get_text()try:self.assertEqual(expect,msg)self.login.page_click_err_btn_ok()except AssertionError:self.login.driver.get_screenshot_as_file("../../image/login_error%s.png" % (time.strftime("%Y_%m_%d %H_%M_%S")))# raise
PO page object 页面 对象
V4 三层结构 base page scripts
base(基类)page页面中一些公共的方法 即抽取公共方法放到base中 (提取方法)
新建Base类 初始化方法 查找元素方法 点击元素方法 输入方法 获取文本方法 截图方法(调用数据)
page(页面对象)一个页面封装成一个对象 通过继承base类 使用其中的公共方法(实现使用)
scripts(业务层 脚本层 )导包调用page页面
from selenium.webdriver.common.by import By
loc = (By.CSS_SELECTOR,".telA")
# loc = By.CSS_SELECTOR,".telA" 也是元组类型
# driver.find_element(By.CSS_SELECTOR,".telA")
print(loc)
# 解包
print(*loc)# ('css selector', '.telA')
# css selector .telA
包和文件夹 包多了init文件
# base
from selenium.webdriver.support.wait import WebDriverWait
import time
from selenium import webdriver
class Base:# 临时替代# def __init__(self, driver):# self.driver = driverdef __init__(self):self.driver = webdriver.Edge()self.driver.get(r"https://demo5.tp-shop.cn/")# 解包只需一次 driver传入即可 loc就是查找元素使用的# 查找元素方法(提供:点击,输入,获取文本)使用def base_find_element(self, loc,timeout=30,poll=0.5): # loc 元组 *loc进行解包# 显示等待return WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll).until(lambda x: x.find_element(*loc))# 点击方法 调用时只需要输入点击哪个元素def base_click(self,loc):self.base_find_element(loc).click()# 输入方法 调用时只需要两个参数 哪个元素 输什么内容def base_input(self,loc,value):el = self.base_find_element(loc)el.clear()el.send_keys(value)# 获取文本方法 哪个元素文本def base_get_text(self,loc):# 一定要返回元素的文本信息return self.base_find_element(loc).text# 截图方法def base_get_image(self):self.driver.get_screenshot_as_file("../../image/login_error%s.png" % (time.strftime("%Y_%m_%d %H_%M_%S")))
# page init
from selenium.webdriver.common.by import By# 登录页面元素配置信息 临时存放地
# 登录链接
login_link = By.PARTIAL_LINK_TEXT, "登录"
# 用户名
login_username = By.ID, "username"
# 密码
login_password = By.ID, "password"
# 验证码
login_verify = By.ID, "verify_code"
# 登录按钮
login_btn = By.CSS_SELECTOR, ".J-login-submit"
# 获取异常文本信息
login_err = By.CSS_SELECTOR, ".layui-layer-content"
# 点击异常提示框文本按钮
login_err_btn_ok = By.CSS_SELECTOR, ".layui-layer-btn0"
#page page_login
from v4 import page
from v4.base.base import Baseclass PageLogin(Base):# 点击登录按钮def page_click_login_lin(self):self.base_click(page.login_link)# 输入用户名def page_input_username(self,username):self.base_input(page.login_username,username)# 输入密码def page_input_password(self,password):self.base_input(page.login_password,password)# 输入验证码def page_input_vertfy_code(self,code):self.base_input(page.login_verify,code)# 点击登录按钮def page_click_login_btn(self):self.base_click(page.login_btn)# 获取提示框文本信息def page_get_err_info(self):return self.base_get_text(page.login_err)# 点击提示框确定按钮def page_click_err_btn_ok(self):self.base_click(page.login_err_btn_ok)# 截图def page_get_image(self):self.base_get_image()# 组装业务登录方法、给业务层调用def page_login(self,username,password,code):self.page_input_username(username)self.page_input_password(password)self.page_input_vertfy_code(code)self.page_click_login_btn()
# scripts 业务层import unittest
from v4.page.page_login import PageLogin
from selenium import webdriver
from parameterized import parameterizeddef get_data():return [("13822223333","123456","8888","账号不存在"),("13822223333","1236","8888","密码错误")]class Test_login(unittest.TestCase):login = None@classmethoddef setUpClass(cls):cls.login = PageLogin()cls.login.page_click_login_lin()@classmethoddef tearDownClass(cls):cls.login.driver.quit()def tearDown(self):self.login.driver.refresh()@parameterized.expand(get_data())def test_login(self,username,password,code,expect):self.login.page_login(username,password,code)msg = self.login.page_get_err_info()try:self.assertEqual(expect,msg)self.login.page_click_err_btn_ok()except AssertionError:self.login.page_get_image()# raise
单例模式:无论实例化多少对象 获取的同一个对象
用处:获取浏览器 都是一个
PO模式分层:面向对象思想 对象库层 操作层 业务层
就是进行三层代码的封装
列表也行 就是麻烦一点 list[0] list[1] 元组直接解包即可
dumps带s时转换 不带s是写json
dumps() 将字典转换成json字符串
json中dump()写入json
loads() 将字符串转为字典
load() 读取json方法
import json# 将字典转换为json字符串data = {"name":"小明","age":18}
print(type(data)) # <class 'dict'>data = json.dumps(data)
print(type(data)) # <class 'str'>print(data)
# {"name": "\u5c0f\u660e", "age": 18} 序列化# 将字符串转为json
data = '{"name":"小明","age":18}' #属性:双引号
print(type(data)) # <class 'str'>data = json.loads(data)
print(type(data)) # <class 'dict'>print(data) # {'name': '小明', 'age': 18} 变成单引号了
JSON文件读写
ctrl+p 查看需要参数
加法测试项目V4PO加数据驱动
Base
base.py Base
from selenium import webdriver
from case_add import pageclass GetDriver:# 设置类属性driver = None# 获取driver@classmethoddef get_driver(cls):if cls.driver is None:# 实例化浏览器cls.driver = webdriver.Edge()# 最大化cls.driver.maximize_window()# 打开浏览器cls.driver.get(page.url)return cls.driver@classmethoddef quit_driver(cls):if cls.driver:print("关闭之前:", cls.driver)cls.driver.quit()print("关闭之后:", cls.driver)cls.driver = Noneprint("置空之后:", cls.driver)if __name__ == '__main__':# 第一次获取浏览器print(GetDriver().get_driver())# 第二次获取浏览器print(GetDriver().get_driver())# 调用关闭,测试 关闭后driver是否为NoneGetDriver().quit_driver()print(GetDriver().get_driver())
虽然是同一个浏览器网址 但是将driver置空后
每次获取浏览器是一个全新的浏览器实例
为了确保在下次获取浏览器时可以重新实例化一个新的浏览器对象,而不是继续使用之前关闭的浏览器对象。
from selenium.webdriver.support.wait import WebDriverWait
import timeclass Base:# 初始化方法def __init__(self, driver):self.driver = driver# 查找元素def base_find_element(self, loc, timeout=30, poll=0.5):""":param loc: 元素的定位信息,格式为元祖:param timeout: 默认超时时间30秒:param poll: 访问频率,默认0.5查找一次元素:return: 返回查找到的元素"""# 显示等待return WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll).until(lambda x: x.find_element(*loc))# 点击def base_click(self, loc):self.base_find_element(loc).click()# 获取value属性方法封装def base_get_element_text(self, loc):# 使用get_attribute()方法获取指定的元素属性值# 注意:返回return self.base_find_element(loc).get_attribute("value")# 截图def base_get_screen_shot(self):self.driver.get_screenshot_as_file("../../image/{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")))
Page
init.py
from selenium.webdriver.common.by import By"""以下为服务器域名配置地址"""
url = r"http://cal.apple886.com/""""以下为计算器配置数据"""
# number = By.CSS_SELECTOR,"#simple{}"calc_add = By.CSS_SELECTOR,"#simpleAdd"
calc_equal = By.CSS_SELECTOR,"#simpleEqual"
calc_get_result = By.CSS_SELECTOR,"#resultIpt"
calc_clear = By.CSS_SELECTOR,"#simpleClearAllBtn"
num = "12345342"for i in num:print("simple{}".format(i))
Page_calc.py 继承Base
PageCalc
from selenium.webdriver.common.by import By
from case_add.base.base import Base
from case_add import pageclass PageCalc(Base):def page_num_click(self, num):for i in str(num):loc = By.CSS_SELECTOR, "#simple{}".format(i)self.base_click(loc)def page_add_btn(self):self.base_click(page.calc_add)def page_equal_btn(self):self.base_click(page.calc_equal)def page_get_result(self):return self.base_get_element_text(page.calc_get_result)def page_clear(self):self.base_click(page.calc_clear)def page_get_screen_shot(self):self.base_get_screen_shot()def page_calc(self, num1, num2):self.page_num_click(num1)self.page_add_btn()self.page_num_click(num2)self.page_equal_btn()
数据驱动
import jsondef read_json(filename):filepath = "../data/"+ filenamewith open(filepath,"r",encoding="utf-8") as f:return json.load(f)if __name__ == '__main__':data = read_json("calc.json")# print(data)# print("---" * 50)list1 = []for i in data.values():list1.append((i.get('a'),i.get('b'),i.get('expect')))print(list1)
业务层
import unittest
from case_add.tool.read_json import read_json
from case_add.base.get_driver import GetDriver
from case_add.page.page_calc import PageCalc
from parameterized import parameterizeddef get_data():data = read_json("calc.json")arr = []for i in data.values():arr.append((i.get('a'), i.get('b'), i.get('expect')))return arrclass TestCal(unittest.TestCase):driver = None@classmethoddef setUpClass(cls):cls.driver = GetDriver.get_driver()cls.calc = PageCalc(cls.driver)@classmethoddef tearDownClass(cls):GetDriver.quit_driver()@parameterized.expand(get_data())def test_calc(self,num1,num2,expect):self.calc.page_calc(num1,num2)result = self.calc.page_get_result()try:self.assertEqual(str(expect),str(result))self.calc.page_clear()except AssertionError:self.calc.base_get_screen_shot()raise
正向和逆向用例是在软件测试中常用的概念。正向用例是使用软件时的预期行为,即用户按照设计好的流程和功能来操作软件系统,以测试系统是否按照预期的方式工作。而逆向用例则是用来测试系统对不符合预期情况的处理能力,即人为制造一些异常情况或错误操作,看系统如何响应。