测试学习记录,仅供参考!
项目实战 5(开源电商商城系统项目)
登录状态
如何区分用户是否已经登录?这里通过在前置操作中去实现,通过传入不同的前置应用操作来此区分登录和非登录的状态;
例如在大部分电子商务商城的应用系统或者需要进行用户身份认证的在线系统中,一个客户与服务器经常经过好几次的交互过程才能完成一笔交易订单或者是一个请求的完成;由于这其中几次交互过程是密切相关的,服务器在进行这些交互过程的某一个交互步骤时往往需要了解上一次或上几次的交互过程处理结果,这就要求所有这些相关的交互过程一般都由一台服务器完成;
在有些要求登录状态的测试场景中,某些情景是要求客户端和服务器之间保持一个会话以记录客户端的各种信息;这里的登录状态是指在 web ui 自动化测试时通过账号和密码的方式来保持会话登录状态的,与平常的 HTTP(HTTPS) 请求中 cookies、session、token 等无必要关系;
cookies:cookie 是一种客户端会话跟踪技术,它将数据存储在客户端浏览器中;通过使用 cookie,可以在浏览器第一次发起请求时,在服务器端设置一个 cookie;cookie 是服务器传递到浏览器,保存在浏览器中的数据,然后浏览器每次请求都带上 cookie,这样就可以标识用哪一个用户发起的请求;
session:session 是一种在服务器端存储用户会话信息的技术,用于在多个请求之间保持用户的状态;session 是把用户的信息保存在服务器上面, 浏览器第一次访问的时候服务器把 sessionID 传递到浏览器,然后浏览器把 Session_id 保存在 cookie 中, 每次访问把 session_id 带上,服务器就可以标识这个请求来自于那个用户,然后根据 session_id 查这个这个用户的 seesion 里面记录了哪些数据,这种方式可以提高数据的安全性和可靠性;
token:当客户端第一次请求会话,发送用户信息到服务端,服务器对用户信息使用加密算法以及密钥进行签名,再将这个签名和数据一次作为 token 返回给客户端,一般情况下服务端不保存 token,由客户端保存 token,当客户端再次请求的话,会将 token 发送给服务端,服务端同样用加密算法和同样的密钥对数据再一次计算签名,和之前 token 中的签名做比较,只要有一个通过了验证,数据信息和资源就能够在任何域上被请求到;在 web 领域中基于 token 的身份验证比较常见,在大多数使用 web API 的互联网应用中,token 是多用户下处理认证的最佳方式;
改造前置应用
1、优化项目根目录 testcase 软件包下 conftest.py 文件(前置操作文件),增加登录状态前置操作应用、非登录状态前置应用操作;
import pytest
from selenium import webdriver
from util_tools.logs_util.recordlog import logs
from config.setting import browser_type, WAIT_TIME
from pageObject.login_page.login_page import LoginPage
@pytest.fixture(autouse=True)
def log_outputs():
logs.info('------测试用例开始执行testcase------')
yield
logs.info('------测试用例执行完毕testcase------')
# @pytest.fixture()
# def get_driver():
# # 将driver设置为全局变量
# global driver
#
# # 初始化浏览器对象--字典
# browser_mapping = {
# 'Chrome': webdriver.Chrome,
# 'Edge': webdriver.Edge,
# 'Firefox': webdriver.Firefox
# }
#
# # 判断配置文件 browser_type 变量值包含在 browser_mapping 字典里面
# if browser_type.capitalize() in browser_mapping:
# driver = browser_mapping.get(browser_type.capitalize())()
#
# # 设置一个全局的隐式等待时间
# driver.implicitly_wait(WAIT_TIME)
# # 最大化浏览器窗口
# driver.maximize_window()
# yield driver
# driver.quit()
def init_driver():
# 初始化浏览器对象--字典
browser_mapping = {
'Chrome': webdriver.Chrome,
'Edge': webdriver.Edge,
'Firefox': webdriver.Firefox
}
# 判断配置文件 browser_type 变量值包含在 browser_mapping 字典里面
if browser_type.capitalize() in browser_mapping:
return browser_mapping.get(browser_type.capitalize())()
@pytest.fixture(scope='class')
def get_driver():
driver = init_driver()
# 设置一个全局的隐式等待时间
driver.implicitly_wait(WAIT_TIME)
# 最大化浏览器窗口
driver.maximize_window()
yield driver
driver.quit()
# 登录状态的前置应用
@pytest.fixture(scope='class')
def login_driver(get_driver):
driver = get_driver
login_page = LoginPage(driver)
# 自行设置是否参数化
login_page.login('admin123', '123456')
return driver
# 未登录状态的前置应用
@pytest.fixture()
def not_login_driver():
driver = init_driver()
# 设置一个全局的隐式等待时间
driver.implicitly_wait(WAIT_TIME)
# 最大化浏览器窗口
driver.maximize_window()
yield driver
driver.quit()
2、如登录测试用例需要用到未登录时的前置操作,可以使用未登录时的前置功能;
3、优化 testcase 软件包 login 目录下 test_login.py 文件;
更改 get_driver 为 not_login_driver;
import pytest
from selenium.webdriver.common.by import By
from time import sleep
from pageObject.login_page.login_page import LoginPage
from util_tools.handle_data.operateJson import read_json
class TestLogin:
# 登录成功
# @pytest.mark.run(order=1) # 指定先运行
# 使用参数化实现一条测试用例跑多种场景--可迭代对象里面有多少组数据就跑多少次测试用例
@pytest.mark.parametrize('data', read_json('./data/login_success.json'))
# 用一个 data(需与上面保持一致) 参数去接收参数化数据
def test_login_success(self, not_login_driver, data):
# 进行列表解包--通过两个参数去接收列表中的数据
username, password = data
# 传浏览器对象--再把结果返回
login_page = LoginPage(not_login_driver)
# 直接调用页面类中的 login 操作--里面需要输入两个参数(参数化传两个参数)
login_page.login(username, password)
# 断言结果
login_page.assert_is_element_present(login_page.assert_result)
sleep(2)
# 登录失败
@pytest.mark.parametrize('data', read_json('./data/login_failed.json'))
def test_login_failed(self, not_login_driver, data):
username, password = data
login_page = LoginPage(not_login_driver)
login_page.login(username, password)
login_page.assert_title('系统提示')
sleep(2)
4、如提交订单测试用例需要用到登录状态下的前置操作;
5、 优化 testcase 软件包 flow 目录下 test_flow.py 文件;
更改 get_driver 为 login_driver;
# 导包
from pageObject.flow_page.flow_page import FlowPage
from time import sleep
class TestFlow:
# 失败场景,购物车没有商品时
def test_purchase_failure(self, login_driver):
flow_page = FlowPage(login_driver)
flow_page.flow_failed()
# 断言没有商品时跳转的url页面地址
assert flow_page.current_url == 'http://localhost:8088/ecshop/flow.php?step=checkout'
sleep(3)
# 成功操作,购物车有商品
def test_purchase_success(self, login_driver):
flow_page = FlowPage(login_driver)
flow_page.flow_success()
# 订单提交成功,断言url
assert flow_page.current_url == 'http://localhost:8088/ecshop/flow.php?step=done'
sleep(3)
6、注册测试用例需要用到未登录时的前置操作;
7、优化 testcase 软件包 register 目录下 test_register.py 文件;
更改 get_driver 为 not_login_driver;
# 导包
from pageObject.register_page.register_page import RegisterPage
import pytest
from time import sleep
from util_tools.handle_data.readYaml import read_yaml
class TestRegister:
# 注册成功场景
@pytest.mark.parametrize('data', read_yaml('./data/register_success.yaml'))
def test_register_success(self, not_login_driver, data):
# 调用页面类相关的操作--直接调用RegisterPage()把浏览器对象get_driver传给它
register_page = RegisterPage(not_login_driver)
# 如果使用 *data 解包数据,data的元素数量必须跟click_register方法的入参个数保持一致
register_page.click_register(*data)
# 添加等待时间查看效果
sleep(3)
# 断言结果
register_page.assert_is_element_present(register_page.assert_result)
# 注册失败场景
@pytest.mark.parametrize('data', read_yaml('./data/register_failed.yaml'))
def test_register_failed(self, not_login_driver, data):
register_page = RegisterPage(not_login_driver)
register_page.click_register(*data)
sleep(3)
register_page.assert_element_not_visible(register_page.assert_result)
# 跳转链接--只是一个按钮,不需要参数化
def test_check_skip_login(self, not_login_driver):
register_page = RegisterPage(not_login_driver)
register_page.skip_login_page()
# 断言结果--直接断言页面url
assert register_page.current_url == 'http://localhost:8088/ecshop/user.php?act=login'
8、 运行测试调试,可以发现提交订单还是没有运行成功,在没有商品的时候,进入不到收货人信息填写、提交订单页面,缺少把商品加入购物车操作;
一个测试用例(页面类)中写多个页面
把商品加入购物车页面
9、在项目根目录 pageObject 软件包 flow_page 目录文件下新建名称一个为 search_page.py 的 Python 文件;把商品加入"购物车"页面;
在首页先点击高级搜索按钮;高级搜索关键字→立即搜索→商品搜索成功出来之后购买
# 导包
from selenium.webdriver.common.by import By
from util_tools.basePage import BasePage
from time import sleep
class SearchPage(BasePage):
url = '/search.php'
# 高级搜索按钮
advanced_search = (By.LINK_TEXT, '高级搜索')
# 关键字搜索框
keywords = (By.NAME, 'keywords')
# 立即搜索按钮
submit = (By.NAME, 'Submit')
# 购买按钮
buy_button = (By.LINK_TEXT, '购买')
def add_cart(self):
"""
点击购买按钮将商品加入购物车中
:return:
"""
self.open_url(self.url)
# 点击高级搜索
self.click(self.advanced_search)
# 搜索框输入数据
self.send_keys(self.keywords, '测试商品抽纸类')
# 点击立即搜索按钮
self.click(self.submit)
sleep(3)
# 商品搜索出来之后点击购买按钮
self.click(self.buy_button)
10、封装完成之后在 test_flow.py 文件中使用(一个测试用例里面使用两个页面类);
# 导包
from pageObject.flow_page.flow_page import FlowPage
from pageObject.flow_page.search_page import SearchPage
from time import sleep
class TestFlow:
# 失败场景,购物车没有商品时
def test_purchase_failure(self, login_driver):
flow_page = FlowPage(login_driver)
flow_page.flow_failed()
# 断言没有商品时跳转的url页面地址
assert flow_page.current_url == 'http://localhost:8088/ecshop/flow.php?step=checkout'
sleep(3)
# 成功操作,购物车有商品
def test_purchase_success(self, login_driver):
# 先将商品加入购物车
search_page = SearchPage(login_driver)
search_page.add_cart()
# 去结算中心提交订单
flow_page = FlowPage(login_driver)
flow_page.flow_success()
# 订单提交成功,断言url
assert flow_page.current_url == 'http://localhost:8088/ecshop/flow.php?step=done'
sleep(3)
11、设置测试数据(data 目录文件下相关文件),运行主函数 run.py 文件,可以运行成功;
未完待续。。。