自动化测试--基于python2.7+selenium+unittest+ddt+yaml搭建框架


前言:selenium api只封装部分,业务公共页面page、连接数据库封装,后续实践后补上。有问题欢迎留言补充,谢谢~

一、框架结构目录

在这里插入图片描述

二、读取文件

utils下新建file_reader.py

# -*- coding: utf-8 -*-
import yaml
import os
from xlrd import open_workbook

class YamlReader:
    def __init__(self, yamlf):
        if os.path.exists(yamlf):
            self.yamlf = yamlf
        else:
            raise FileNotFoundError('文件不存在!')
        self._data = None

    @property
    def data(self):
        # 如果是第一次调用data,读取yaml文档,否则直接返回之前保存的数据
        if not self._data:
            with open(self.yamlf, 'rb') as f:
                self._data = list(yaml.safe_load_all(f))  # load后是个generator,用list组织成列表
        return self._data
        
class SheetTypeError(Exception):
    pass

# 读取excel文件中的内容。返回list。
class ExcelReader:
    """
    如:
    excel中内容为:
    | A  | B  | C  |
    | A1 | B1 | C1 |
    | A2 | B2 | C2 |

    如果 print(ExcelReader(excel, title_line=True).data),输出结果:
    [{A: A1, B: B1, C:C1}, {A:A2, B:B2, C:C2}]

    如果 print(ExcelReader(excel, title_line=False).data),输出结果:
    [[A,B,C], [A1,B1,C1], [A2,B2,C2]]

    可以指定sheet,通过index或者name:
    ExcelReader(excel, sheet=2)
    ExcelReader(excel, sheet='BaiDuTest')
    """
    def __init__(self, excelpath, sheet=0, title_line=True):
        if os.path.exists(excelpath):
            self.excelpath = excelpath  # excel文件路径
        else:
            raise FileNotFoundError('文件不存在!')
        self.sheet = sheet   # sheet可以是int表示表格的索引,可以是str表示表格的名称
        self.title_line = title_line  # 是否存在标题行,有标题行,每一行都是都是对应列名的取值;没有标题行,每一行都是一个列表
        self._data = list()   # 用于存储每行生成的数据。

    @property
    def data(self):
        if not self._data:
            workbook = open_workbook(self.excelpath)
            if type(self.sheet) not in [int, str]:
                raise SheetTypeError('Please pass in <type int> or <type str>, not {0}'.format(type(self.sheet)))
            elif type(self.sheet) == int:
                s = workbook.sheet_by_index(self.sheet)
            else:
                s = workbook.sheet_by_name(self.sheet)

            if self.title_line:
                title = s.row_values(0)  # 首行为title
                for col in range(1, s.nrows):
                    # 依次遍历其余行,与首行组成dict,拼到self._data中
                    self._data.append(dict(zip(title, s.row_values(col))))
            else:
                for col in range(0, s.nrows):
                    # 遍历所有行,拼到self._data中
                    self._data.append(s.row_values(col))
        return self._data

if __name__ == '__main__':
    y = 'D:\myProject\config\config.yml'
    reader = YamlReader(y)
    print(reader.data)
    
    e = 'D:/myProject/data/baidu.xlsx'
    reader = ExcelReader(e, title_line=True)
    print(reader.data)

三、配置文件config.py

utils下新建config.py

#-*- coding: utf-8 -*-
import os
from utils.file_reader import YamlReader

# 通过当前文件的绝对路径,其父级目录一定是框架的base目录,然后确定各层的绝对路径。如果你的结构不同,可自行修改。
# 之前直接拼接的路径,修改了一下,用现在下面这种方法,可以支持linux和windows等不同的平台,也建议大家多用os.path.split()和os.path.join(),不要直接+'\\xxx\\ss'这样
BASE_PATH = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]
CONFIG_FILE = os.path.join(BASE_PATH, 'config', 'config.yml')
DATA_PATH = os.path.join(BASE_PATH, 'data')
DRIVER_PATH = os.path.join(BASE_PATH, 'drivers')
LOG_PATH = os.path.join(BASE_PATH, 'log')
REPORT_PATH = os.path.join(BASE_PATH, 'report')

class Config:
    def __init__(self, config=CONFIG_FILE):
        self.config = YamlReader(config).data

    def get(self, element, index=0):
        """
        yaml是可以通过'---'分节的。用YamlReader读取返回的是一个list,第一项是默认的节,如果有多个节,可以传入index来获取。
        这样我们其实可以把框架相关的配置放在默认节,其他的关于项目的配置放在其他节中。可以在框架中实现多个项目的测试。
        """
        return self.config[index].get(element)

config目录下新建config.yml

URL: http://www.baidu.com    # 测试网址
emailserver: smtp.qq.com    #发件箱邮件服务
from_user: XXXXXX@qq.com
from_passwd: tkmyrvvwigmwbihe
to_user: XXXXXXXX@qq.com
#mysql
mysql:
    ip: '192.168.3.6'
    user: 'root'
    pwd: 'password'
    db: 'mysql'
#oracle
oracle:
    ip: '192.168.3.1'
    user: 'root'
    pwd: 'password'
    port: '1521'
    sid: 'barc'

log:
    file_name: testcase.log      # 输出日志文件名
    backup: 5                # 备份名
    console_level: WARNING  # 控制台输出等级
    file_level: DEBUG       # 文件输出等级
    pattern: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'  # 打印输出格式

四、日志

utils下新建logger.py

# -*- coding: utf-8 -*-
import logging
import os
import unittest
import time
import os.path

class Logger(object):
    def __init__(self, logger, CmdLevel=logging.INFO, FileLevel=logging.INFO):
        self.logger = logging.getLogger(logger)
        self.logger.setLevel(logging.DEBUG)  # 设置日志默认级别为DEBUG
        fmt = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s')  # 设置日志输出格式
        currTime = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))  # 格式化当前时间
        log_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]+'/log/'
        print('得到的日志路径为:', log_path)
        log_name = log_path + currTime + '.log'  # 设置日志文件名称

        # 设置由文件输出
        fh = logging.FileHandler(log_name, encoding='utf-8')  # 采用utf-8字符集格式防止出现中文乱码
        fh.setFormatter(fmt)
        fh.setLevel(FileLevel)  # 日志级别为INFO

        # 设置日志由控制台输出
        # sh = logging.StreamHandler(log_name)
        # sh.setFormatter(fmt)
        # sh.setLevel(CmdLevel)
        self.logger.addHandler(fh)  # 添加handler
        
    def getlog(self):
        return self.logger

if __name__ == '__main__':
    unittest.main()

五、封装浏览器

utils下新建browserengine.py

# -*- coding: utf-8 -*-
from selenium import webdriver
import configparser
import sys, os

class BrowserEngine(object):
    def __init__(self, driver):
        self.driver = driver
    browser_type = "Chrome"  
    def get_browser(self):
        if self.browser_type == 'Firefox':
            driver = webdriver.Firefox()
        elif self.browser_type == 'Chrome':
            driver = webdriver.Chrome()
        elif self.browser_type == 'IE':
            driver = webdriver.Ie()
        else:
            driver = webdriver.Chrome()
            
        driver.maximize_window()
        driver.implicitly_wait(10)

        return driver

六、封装数据库

utils下新建conndb.py

#-*- coding: utf-8 -*-
import cx_Oracle,pymysql,json,os
from utils.config import Config
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'

myora = Config().get('oracle')
mysql = Config().get('mysql')

class TestDb(object):
    def __init__(self,oracle_type):
        if oracle_type == 'oracle':
            self.connect = cx_Oracle.connect(myora['user'] + "/" + myora['pwd'] + "@" + myora['ip'] + ":" + myora['port'] + "/" + myora['sid'])
            self.cursor = self.connect.cursor()
        elif oracle_type == 'mysql':
            self.connect = pymysql.connect(mysql['ip'], mysql['user'], mysql['pwd'], mysql['db'])
            self.cursor = self.connect.cursor()
        else:
            print("请连接正确的数据库")

    def select(self,sql):
        try:
            self.cursor.execute(sql)
            result = self.cursor.fetchall()
            print('查询数据成功')
            return result
        except Exception as e:
            print(e)
        finally:
            self.disconnect()

        #返回json串脚本
        # list = []
        # self.cursor.execute(sql)
        # result = self.cursor.fetchall()
        # col_name = self.cursor.description
        # for row in result:
        #     dict = {}
        #     for col in range(len
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值