• web自动化测试


    一.整体结构

    使用了数字驱动(DDT)和页面驱动(POM)测试,结合数据管理,报告管理,配置管理,日志管理。

    common包:封装公共方法类,比如获取配置文件数据,获取日志对象,获取屏幕截图等。
    config包:用于存放配置文件。
    data包:数据文件,用于数据驱动。
    log包:用于存放日志文件数据。
    report包:用于存放测试报告文件。
    screanshots包:存放截图文件。
    test_case包:存放测试类的模块。
    pages包:一个页面对应一个page类。
    test_run包:执行自动化测试用例。

    二.web自动化测试实现

    1.路径配置文件

    config包的config.yaml

    loggerConfigPath: ../config/logger.conf
    screenshotPath: ../screenshots
    testUrl: 'https://www.baidu.com/'
    testData: ../data/login_data.csv
    caseDir: ../test_case
    reportDir: ../report
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.日志格式文件(可当模板使用)

    config包的logger.conf

    [loggers]
    keys=root,infoLogger
    
    [logger_root]
    level=INFO
    handlers=consoleHandler,fileHandler
    
    [logger_infoLogger]
    handlers=consoleHandler,fileHandler
    qualname=infoLogger
    propagate=0
    
    [handlers]
    keys=consoleHandler,fileHandler
    
    [handler_consoleHandler]
    class=StreamHandler
    level=INFO
    formatter=form02
    args=(sys.stdout,)
    
    [handler_fileHandler]
    class=FileHandler
    level=INFO
    formatter=form01
    args=('../log/ggmzx.log', 'a')
    
    [formatters]
    keys=form01,form02
    
    [formatter_form01]
    format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
    
    [formatter_form02]
    format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.公用方法(读取配置文件,读取测试数据,获取截图和日志)

    common包的util.py

    import yaml
    import logging.config
    import csv
    
    
    class Util:
    
        # 获取路径配置文件
        @classmethod
        def get_conf(cls):
            with open('../config/config.yaml', 'r', encoding='UTF8') as f:
                data = yaml.load(f, Loader=yaml.FullLoader)
                return data  # 以字典格式返回配置文件中的内容
    
        # 获取截图
        @classmethod
        def get_screenshot(cls, driver, path):
            driver.get_screenshot_as_file(path)
    
        # 读取测试数据文档
        @classmethod
        def get_testdata_by_row(cls, csv_file, line):
            logger.info('======开始读取csv file======')
            with open(csv_file, 'r', encoding='UTF8') as f:
                reader = csv.reader(f)
                for index, row in enumerate(reader, 1):
                    if index == line:
                        return row
    
    
    # 日志配置
    conf_file = Util.get_conf()['loggerConfigPath']
    logging.config.fileConfig(conf_file)
    logger = logging.getLogger()
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    4.每条测试用例,执行前需要打开浏览器,进入网址,执行结束关闭浏览器

    common包的myunit.py

    import unittest
    from selenium import webdriver
    from common.util import logger, Util
    
    
    class MyUnit(unittest.TestCase):
    
        def setUp(self) -> None:
            logger.info('===========启动测试setUp===========')
            self.driver = webdriver.Chrome()
            self.driver.get(Util.get_conf()['testUrl'])
            self.driver.implicitly_wait(10) # 等待时长
    
        def tearDown(self) -> None:
            logger.info('===========结束测试setUptearDown===========')
            self.driver.quit()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    5.页面操作

    pages包的base_page.py封装页面常用方法

    
    
    class BasePage:
    
        def __init__(self, driver):
            self.driver = driver
    
        def find_element(self, *loc):
            return self.driver.find_element(*loc)
    
        def find_elements(self, *loc):
            return self.driver.find_elements(*loc)
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    pages 包的login_page.py 登录页面的操作

    import time
    from pages.base_page import BasePage
    from selenium.common.exceptions import NoSuchElementException
    from common.util import logger, Util
    
    
    class LoginPage(BasePage):   # 定义登录页面对象的属性和方法
    
        username = ('id', 'userName')
        password = ('id', 'passsword')
        login_btn = ('xpath', '//*[@id="app"]/section/div/div[2]/div/div[3]/form/div[3]/div/div/span/button[1]')
        welcome_msg = ('xpath', '//*[@id="app"]/section/section/section/div/div[1]/header/div/div/div/span')
    
        def login_action(self, un, pw):
            logger.info('=======开始进行登录操作===========')
            logger.info('输入用户名{}'.format(un))
            self.find_element(*self.username).send_keys(un)
            time.sleep(1)
            logger.info('输入名密码{}'.format(pw))
            self.find_element(*self.password).send_keys(pw)
            time.sleep(1)
            logger.info('点击登录按钮')
            self.find_element(*self.login_btn).click()
            time.sleep(1)
    
        def check_login_status(self):
            now = time.strftime('%Y-%m-%d %H %M %S')
            try:
                str_welcome = self.find_element(*self.welcome_msg).text
            except NoSuchElementException:
                logger.error('========登录失败=======')
    
                Util.get_screenshot(self.driver, Util.get_conf()['screenshotPath']+now)
                return False
            else:
                if 'admin' in str_welcome:
                    logger.info('=======登录成功=======')
                    return True
                else:
                    logger.error('========登录失败=======')
                    Util.get_screenshot(self.driver, Util.get_conf()['screenshotPath']+now)
                    return False
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    6.测试用例的执行

    test_case包的test_login.py 登录页面的执行

    from common.myunit import MyUnit
    from pages.login_page import LoginPage
    from common.util import Util
    import time
    
    class LoginTest(MyUnit):
        def test_login_success(self):
            lp = LoginPage(self.driver)
            data = Util.get_testdata_by_row(Util.get_conf()['testData'], 1)
            lp.login_action(data[0], data[1])
            time.sleep(1)
            self.assertTrue(lp.check_login_status())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    7.运行所有测试用例,即test_case包里面的程序

    test_run包的run.py

    import unittest
    import time
    from HTMLTestRunner import HTMLTestRunner
    from common.util import Util
    
    test_dir = Util.get_conf()['caseDir']
    report_dir = Util.get_conf()['reportDir']
    
    dis = unittest.defaultTestLoader.discover(test_dir, pattern="test*.py")
    
    now = time.strftime('%Y-%m-%d %H:%M:%S')
    report_name = report_dir + '/' + now + ' test_report.html'
    
    runner = HTMLTestRunner(
        title='金融服务自动化测试报告',
        description='V0.1测试结果',
        stream=open(report_name, 'wb'),
        verbosity=2
    )
    runner.run(dis)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    8.测试数据文件

    data包的login_data.csv

    admin,admin123

    9.添加其他测试用例

    在pages包添加页面操作类,然后在test_case包添加测试用例执行类

  • 相关阅读:
    强大的Nginx配置生成器
    【数据分享】2005-2022年全国民航机场客货吞吐量和起降架次数据
    Servlet工作过程和生命周期
    【MySQL】如何使用SQL语句获取表结构和获取全部表名
    代码随想录刷题|完全背包理论基础 LeetCode 518. 零钱兑换II 377. 组合总和 Ⅳ
    练习-Java循环while之等差数列均值
    智慧燃气,如何能够防患于未“燃”!
    基于安卓Android银行排队叫号系统设计与实现
    万物皆可集成系列:低代码对接企企云实现数据集成
    【重拾Java系列】—— 集合之Collection
  • 原文地址:https://blog.csdn.net/XGZ2IT/article/details/126909739