Skip to content

【实战】电子商务产品实战


目录

  • 产品分析
  • 测试用例分析
  • 编写脚本
  • 脚本优化
  • 生成测试报告

产品分析

  • 产品:litemall管理后台
  • 功能:商品类目
  • 使用账户 - 用户名: manage - 密码: manage123

http://litemall.hogwarts.ceshiren.com/#/dashboard


测试用例分析

用例标题 前提条件 用例步骤 预期结果 实际结果
添加商品类目 1. 登录并进入用户管理后台
2. 登录账号有商场管理的权限
1. 点击增加
2. 输入类目名称
3. 点击确定
1. 跳转商品类目列表
2. 新增在最后一行,新增成功
删除商品类目 1. 进入用户管理后台
2. 商品列表里面有已存在的商品(新增)
1. 点击删除按钮 1. 是否有删除成功提示
2. 被删除商品不在商品类目列表展示

编写脚本思路

uml diagram


前置后置

  • 在setup_class打开浏览器
  • teardown_class关闭浏览器进程
  • 添加隐式等待配置
class TestLitemall:
    def setup_class(self):
        # 打开浏览器
        self.driver = webdriver.Chrome()
        # 添加隐式等待配置
        self.driver.implicitly_wait(3)

    def teardown_class(self):
        # 关闭浏览器进程
        self.driver.quit()

初步实现功能

  • 登录功能
  • 新增功能
  • 删除功能
  • 整体调试
"""
__author__ = '霍格沃兹测试开发学社'
__desc__ = '更多测试开发技术探讨,请访问:https://ceshiren.com/t/topic/15860'
"""
import time

from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


class TestLitemall:

    def setup_class(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(3)
        self.driver.get("http://litemall.hogwarts.ceshiren.com")
        # 登录功能,因为只需要登录一次,所以放在setup_class
        self.driver.find_element(By.NAME, "username").clear()
        self.driver.find_element(By.NAME, "username").send_keys("manage")
        self.driver.find_element(By.NAME, "password").clear()
        self.driver.find_element(By.NAME, "password").send_keys("manage123")
        self.driver.find_element(By.XPATH, "//*[text()='登录']").click()

    def teardown_class(self):
        self.driver.quit()

    # 新增商品类目功能
    def test_add_product_type(self):
        self.driver.find_element(
            By.XPATH, "//*[text()='商场管理']").click()
        self.driver.find_element(
            By.XPATH, "//*[text()='商品类目']").click()
        self.driver.find_element(
            By.XPATH, "//*[text()='添加']").click()
        self.driver.find_element(
            By.CSS_SELECTOR, ".el-input__inner").send_keys("添加商品操作")
        time.sleep(3)
        self.driver.find_element(
            By.CSS_SELECTOR, ".dialog-footer .el-button--primary").click()
        eles = self.driver.find_elements(
            By.XPATH, "//*[text()='添加商品操作']")
        self.driver.find_element(
            By.XPATH, "//*[text()='添加商品操作']/../..//*[text()='删除']").click()
        assert eles != []
    # 删除商品类目功能
    def test_delete_type(self):
        self.driver.find_element(
            By.XPATH, "//*[text()='商场管理']").click()
        self.driver.find_element(
            By.XPATH, "//*[text()='商品类目']").click()
        self.driver.find_element(
            By.XPATH, "//*[text()='添加']").click()
        self.driver.find_element(
            By.CSS_SELECTOR, ".el-input__inner").send_keys("删除商品操作")
        time.sleep(3)
        self.driver.find_element(
            By.CSS_SELECTOR, ".dialog-footer .el-button--primary").click()
        self.driver.find_element(
            By.XPATH, "//*[text()='删除商品操作']/../..//*[text()='删除']").click()
        time.sleep(3)
        eles = self.driver.find_elements(By.XPATH, "//*[text()='删除商品操作']")
        assert eles == []

代码优化

  • 强制等待全部替换为显式等待
  • 使用expected_conditions提供的方法
  • 自定义显式等待条件
  • 注意:代码片段,不要直接复制粘贴
# 注意:代码片段,不要直接复制粘贴
# 使用`expected_conditions`提供的方法
WebDriverWait(self.driver, 10).until_not(
expected_conditions.visibility_of_any_elements_located(
(By.XPATH, "元素定位")))

# 自定义显式等待条件
def click_execption(by, element, attempts=5):
    def _inner(driver):
        """
        多次点击同个按钮
        :param driver:
        :return:
        """
        count = 0 # 实际循环次数
        while count<attempts:
            try:
                count +=1
                # 因为点击的过程可能出现报错,所以需要添加try 捕获报错的异常
                driver.find_element(by, element).click()
                return True
            except Exception:
                print("出现异常啦")
        return False
    return _inner

# 使用自定义的显式等待条件
WebDriverWait(self.driver,10).\
    until(click_execption(
    By.CSS_SELECTOR, "元素定位"))

添加日志

  • 日志配置
# 日志配置
import logging
# 创建logger实例
logger = logging.getLogger('simple_example')
# 设置日志级别
logger.setLevel(logging.DEBUG)
# 流处理器
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# 日志打印格式
formatter = logging.Formatter\
('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 添加格式配置
ch.setFormatter(formatter)
# 添加日志配置
logger.addHandler(ch)

添加截图

  • save_screenshot 方法
  • 提前创建图片保存路径
timestamp = int(time.time())
# 前提-在当前路径需要有一个images 文件夹
file_path = f"./images/screenshot_{timestamp}.png"
self.driver.save_screenshot(file_path)
allure.attach.file(file_path, name="pic", 
                                        attachment_type=allure.attachment_type.PNG)

生成测试报告

  • 前提条件: - 安装Allure程序 - 安装allure-pytest插件
# 执行测试用例,生成测试报告数据
pytest 用例文件 --alluredir=报告路径
# 生成测试报告在线地址
allure serve 报告路径

目前脚本存在的问题

  • 很多重复代码,维护困难
  • 没有办法清晰的描述业务场景

学习PO设计模式之后解决这些问题