目录
- 1 自动化测试流程
- 2 项目介绍
- 2.1 项目功能和技术
- 2.2 项目简介
- 2.3 用例设计
- 2.4 编写代码
- 2.4.1 公共方法
- 2.4.2 抽取PO
- 2.5 视频
1 自动化测试流程
步骤:
- 需求分析
- 挑选适合做自动化测试的功能【人力不足时,选择冒烟测试】
- 设计并筛选测试用例
- 搭建自动化测试环境
- 设计自动化测试项目的架构
- 编写代码
- 执行测试用例
- 生成测试报告并分析结果
2 项目介绍
2.1 项目功能和技术
- 业务特性
- 用户和角色
- 功能模块
- 技术栈
2.2 项目简介
项目名称
TPShop开源商城系统
项目描述
TPShop是一个电子商务B2C电商平台系统,功能强大安全便捷。适合企业及个人快速构建个性化网上商城
包含PC+IOS客户端+Android客户端+微商城,系统PC+后台是基于ThinkPHP MVC构架开发的跨平台开源软件设计得非常灵活,具有模块化架构体系和丰富的功能,易于与第三方应用系统无缝集成,在设计上,包含相当全面,以模块化架构体系,让应用组合变得相当灵活,功能也相当丰富
项目架构
Windows + PHP + Apache + MySQL
2.3 用例设计
编写规则
- 自动化测试用例一般只实现核心业务流程或者重复率较高功能
- 自动化测试用例的选择一般以“正向”逻辑的验证为主
- 不是所有手工测试用例都可以使用自动化测试
- 尽量减少多个用例脚本之间的依赖
- 自动化测试执行用例完毕后,一般需要回归原点
2.4 编写代码
2.4.1 公共方法
base.action.py
class BaseAction:
# 初始化驱动
def __init__(self, driver):
self.driver = driver
# 查找单个元素
def find_el(self, feature):
return self.driver.find_element(*feature)
# 查找多个元素
def find_els(self, feature):
return self.driver.find_elements(*feature)
# 查找按钮元素
def click(self, feature):
return self.find_el(feature).click()
# 查找输入元素
def input(self, feature, content):
return self.find_el(feature).send_keys(content)
# 清空
def clear(self, feature):
return self.find_el(feature).clear()
# 定位数字按钮
def find_el_num(self, feature, num):
return self.driver.find_element(feature[0], feature[1].format(str(num)))
# 切换指定的页面
def switch_to(self, frame_feature):
return self.driver.switch_to.frame(self.find_el(frame_feature))
# 切换回默认页面
def switch_to_default(self):
return self.driver.switch_to_default_content()
# 切换新窗口
def switch_windows(self):
handles = self.driver.window_handles()
return self.driver.switch_to(handles[-1])
driver_utils.py
# 获取/关闭浏览器驱动的类
from selenium import webdriver
class DriverUtils:
__driver = None
__switch = True
# 获取浏览器驱动
@classmethod
def get_driver(cls):
if cls.__driver is None:
cls.__driver = webdriver.Chrome()
cls.__driver.maximize_window()
cls.__driver.implicitly_wait(10)
return cls.__driver
# 关闭浏览器驱动
@classmethod
def quit_driver(cls):
if cls.__driver is not None and cls.__switch is False:
cls.__driver.quit()
cls.__driver = None
# 设置浏览器开关
@classmethod
def set_switch(cls, switch):
cls.__switch = switch
read_data.py
# 读取data数据文件
import json
def read_data(filename):
with open("./data/" + filename, "r", encoding="utf-8") as f:
list_data = []
dict_list = json.load(f)
for value in dict_list.values():
list_data.append(value)
return list_data
2.4.2 抽取PO
1. 定义页面对象
首页:index_page.py
# 首页
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class IndexPage(BaseAction):
# 登录链接
login_link_btn = By.CLASS_NAME, "red"
# 搜索框
search_input = By.ID, "q"
# 搜索 按钮
search_btn = By.CLASS_NAME, "ecsc-search-button"
# 购物车 链接
my_cart_link = By.CLASS_NAME, "c-n"
# 我的订单 链接
my_order_link = By.XPATH, "/html/body/div[1]/div[1]/div/ul/li[1]/a"
# 点击首页的"登录"链接, 进入登录页面
def click_login_link(self):
return self.click(self.login_link_btn)
# 输入关键字,进行搜索商品
def input_keywords(self, content):
return self.input(self.search_input, content)
# 点击搜索按钮
def click_search_btn(self):
return self.click(self.search_btn)
# 点击"我的订单"链接
def click_my_order_link(self):
return self.click(self.my_order_link)
# 点击"我的购物车"链接
def click_my_cart_link(self):
return self.click(self.my_cart_link)
登录页:login_page.py
# 登录页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class LoginPage(BaseAction):
# 登录链接 按钮
login_link_btn = By.CLASS_NAME, "red"
# 用户名 输入框
username_input = By.ID, "username"
# 密码 输入框
password_input = By.ID, "password"
# 验证码 输入框
verify_code_input = By.ID, "verify_code"
# 登录 按钮
login_btn = By.NAME, "sbtbutton"
# 点击首页的"登录"链接, 进入登录页面
def click_login_link(self):
return self.click(self.login_link_btn)
# 输入用户名
def input_username(self, content):
return self.input(self.username_input, content)
# 输入密码
def input_password(self, content):
return self.input(self.password_input, content)
# 输入验证码
def input_verify_code(self, content):
return self.input(self.verify_code_input, content)
# 点击登录按钮
def click_login_btn(self):
return self.click(self.login_btn)
个人中心页:home_page.py (登录成功之后会跳转到该页面)
# 个人中心页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class HomePage(BaseAction):
# 立即支付 按钮
pay_btn = By.CLASS_NAME, "ps_lj"
# 待付款标签
pend_pay = By.XPATH, "//*[text()='待付款']"
# 点击立即付款按钮
def click_immed_pay_btn(self):
return self.click(self.pay_btn)
# 点击付款链接
def click_pay_btn(self):
return self.click(self.pend_pay)
商品搜索页:goods_search_page.py(搜索商品之后的页面,即搜索后的列表)
# 商品搜索页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class GoodsSearchPage(BaseAction):
# 加入购物车
add_cart_btn = By.XPATH, "/html/body/div[4]/div/div[2]/div[2]/ul/li[1]/div/div[5]/div[2]/a"
# 点击加入购物车按钮
def click_add_cart_btn(self):
return self.click(self.add_cart_btn)
商品详情页:goods_detail_page.py
# 商品详情页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class GoodsDetailPage(BaseAction):
# 加入购物车
details_add_cart_btn = By.CSS_SELECTOR, ".addcar"
# iframe
cart_iframe = By.CSS_SELECTOR, "[id*='layui-layer-iframe']]"
# 加入购物车成提示语
result_msg = By.CSS_SELECTOR, "#addCartBox > div.colect-top > div > span"
# 点击加入购物车 按钮
def click_details_add_cart_btn(self):
return self.click(self.details_add_cart_btn)
# 获取弹窗框的结果
def get_result(self):
# 切换到iframe中,再获取结果
self.switch_to(self.cart_iframe)
return self.find_el(self.result_msg).text
购物车页:cart_page.py
# 购物车页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class CartPage(BaseAction):
# 结算按钮
go_to_btn = By.CLASS_NAME, "gwc-qjs"
# 点击结算按钮
def click_go_to_btn(self):
return self.click(self.go_to_btn)
下订单页:order_page.py
# 下订单页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class OrderPage(BaseAction):
# 提交订单按钮
submit_btn = By.CLASS_NAME, "Sub-orders"
# 点击提交订单按钮
def click_submitr_btn(self):
return self.click(self.submit_btn)
订单支付页:order_pay_page.py
# 订单支付页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction
class OrderPayPage(BaseAction):
# 订单状态信息
tips_info = By.XPATH, "/html/body/div[2]/div/div[2]/div[1]/h3"
# 货到付款选择
arrived_pay = By.XPATH, "//input[@value='pay_code=cod']"
# 确认支付方式 按钮
pay_btn = By.CLASS_NAME, "button-confirm-payment"
# 获取订单状态信息
def click_tips_info(self):
return self.find_el(self.tips_info).text
# 点击货到付款选框
def click_arrived_pay(self):
return self.click(self.arrived_pay)
# 确认支付方式 按钮
def click_pay_btn(self):
return self.click(self.pay_btn)
总结: 首先根据测试流程,简写出每一步关键词(流程),根据页面再写出属性和方法
2. 编写测试脚本
登录模块:test_login.py
# 导包
import json
import time
import pytest
from page.index_page import IndexPage
from page.login_page import LoginPage
from utils.driver_utils import DriverUtils
from utils.read_data import read_data
# 定义测试类
class TestLogin:
def setup_method(self):
self.driver = DriverUtils.get_driver()
DriverUtils.set_switch(True)
self.login_page = LoginPage(self.driver)
self.index_page = IndexPage(self.driver)
self.driver.get("http://192.168.157.137")
def teardown_method(self):
time.sleep(5)
DriverUtils.quit_driver()
@pytest.mark.parametrize("params", read_data("login_data.json"))
def test_login(self, params):
# 1. 点击首页的"登录"链接, 进入登录页面
self.index_page.click_login_link()
# 2. 输入用户名
self.login_page.input_username(params["username"])
# 3. 输入一个错误密码
self.login_page.input_password(params["password"])
# 4. 输入验证码
self.login_page.input_verify_code(params["code"])
# 5. 点击登录按钮
self.login_page.click_login_btn()
# 暂停5秒,等待跳转
time.sleep(5)
# 断言,判断页面的title,是否一致
assert params["msg"] in self.driver.title
购物车模块:test_cart.py
import logging
import time
import pytest
from page.cart_page import CartPage
from page.goods_detail_page import GoodsDetailPage
from page.goods_search_page import GoodsSearchPage
from page.index_page import IndexPage
from utils.driver_utils import DriverUtils
from utils.read_data import read_data
class TestCart:
def setup_method(self):
self.driver = DriverUtils.get_driver()
self.index_page = IndexPage(self.driver)
self.goods_search_page = GoodsSearchPage(self.driver)
self.goods_detail_page = GoodsDetailPage(self.driver)
self.driver.get("http://192.168.157.137")
def teardown_method(self):
time.sleep(5)
DriverUtils.quit_driver()
@pytest.mark.parametrize("params", read_data("cart_data.json"))
def test_search_to_cart(self, params):
# 1. 点击首页搜索框输入关键字
self.index_page.input_keywords(params["keywords"])
# 2. 点击搜索按钮
self.index_page.click_search_btn()
logging.info("search XiaoMiPhone")
# 3. 点击搜索列表“加入购物车”按钮
self.goods_search_page.click_add_cart_btn()
# 4. 在商品详情页面,点击添加购物车
self.goods_detail_page.click_details_add_cart_btn()
# 等待弹窗,5秒之后
time.sleep(5)
logging.info("wait 5s for the page to display")
# 断言,查看是否"添加成功"字样
assert params["msg"] == self.goods_detail_page.get_result()
订单模块:testt_order.py
import logging
import time
import pytest
from page.cart_page import CartPage
from page.home_page import HomePage
from page.index_page import IndexPage
from page.order_page import OrderPage
from page.order_pay_page import OrderPayPage
from utils.driver_utils import DriverUtils
from utils.read_data import read_data
class TestOrder:
def setup_method(self):
self.driver = DriverUtils.get_driver()
self.index_page = IndexPage(self.driver)
self.order_page = OrderPage(self.driver)
self.order_pay_page = OrderPayPage(self.driver)
self.cart_page = CartPage(self.driver)
self.home_page = HomePage(self.driver)
self.driver.get("http://192.168.157.137")
def teardown_method(self):
time.sleep(5)
self.driver.get_screenshot_as_file("./screenshot/tpshop.png")
DriverUtils.quit_driver()
@pytest.mark.parametrize("params", read_data("order_data.json"))
def test_submit_order(self, params):
# 1. 首页点击"我的购物车"
self.index_page.click_my_cart_link()
# 2. 点击去结算
self.cart_page.click_go_to_btn()
logging.info("go settle")
# 等待5秒
time.sleep(5)
logging.info("wait 5s for the page to display")
# 1. 点击提交订单按钮
self.order_page.click_submitr_btn()
logging.info("submit order")
# 断言,判断状态信息是否正确
assert params["msg"] == self.order_pay_page.click_tips_info()
@pytest.mark.parametrize("params", read_data("pay_data.json"))
def test_pay(self, params):
# 1. 点击"我的订单"
self.index_page.click_my_order_link()
time.sleep(5)
# 2. 在个人中心点击”待付款“
self.home_page.click_immed_pay_btn()
time.sleep(5)
# 3. 点击立即支付按钮
self.home_page.click_pay_btn()
time.sleep(5)
# 4. 点击选择货到付款
self.order_pay_page.click_arrived_pay()
# 5. 点击确认支付方式按钮
self.order_pay_page.click_pay_btn()
logging.info("Confirm payment")
time.sleep(5)
logging.info("wait 5s for the page to display")
# 断言 状态
assert params["msg"] == self.order_pay_page.click_tips_info()
注意: 建议每个功能模块对应一个py文件
3. 日志配置类
import logging.handlers
def set_log_config():
# 创建日志器对象
logger = logging.getLogger()
# 设置日志器级别
logger.setLevel(level=logging.DEBUG)
# 创建处理器对象 输出到控制台
ls = logging.StreamHandler()
lf = logging.handlers.TimedRotatingFileHandler(filename="./log/tshop.log", when="d", backupCount=3)
# 创建格式器对象
fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s:%(funcName)s:%(lineno)d] - %(message)s"
formartter = logging.Formatter(fmt=fmt)
# 将格式器添加到处理器
ls.setFormatter(formartter)
lf.setFormatter(formartter)
# 将处理器添加到日志器
logger.addHandler(ls)
logger.addHandler(lf)