学习日记

2.23 星期五

# todo 2/22
# 自动化测试框架 测试报告 写用例 运行用例 日志/失败截图 筛选用例/重运行功能 方便冒烟和回归的分别
# unittest pytest 区别 重新运行失败的用例  筛选用例 加载测试用例
# 设置pytest运行模式 已test Test 开头的函数和类
# 表达用例
# unittest 定义一个类 继承unittest.TestCase
# pytest   设置pytest运行模式 已test Test 开头的函数和类
# 断言 self.assert   assert 表达式  为true
# 收集用例  unittest TestLoader.discover类 TestSuite   pytest 自动收集用例
# 命令行 当前目录 pytest  收集 。py  test_    _test结尾  Test开头的类  test开头的函数
# 执行顺序  文件名 ascll码顺序   文件内是按代码的先后顺序执行
# fixture  前置后置
#  unittest setup、teardown  setupclass teardownclass
# pytest function class  module session
# 插件  pytest 700+ html报告 allure 报告 重运行
# 筛选用例  打标记 目的筛选回归和冒烟用例  命令行运行过滤 pytest  -s -v -m  maoyan
# 先注册标签    在@pytest.mack.maoyan
# 模块打标记  pytestmark = pytest.mark.maoyan

2.19 星期五

# todo 2/11
# todo 上传文件操作封装
import pywintypes
#import pythoncom # Uncomment this if some other DLL load will fail
import win32gui
import win32con

# 前提Windows上传窗口已经出现,sleep1-2秒等待弹窗出现
def upload(filepath,brower_type = "chrome"):
    if brower_type == "chrome":
        title = "打开"
    else:
        title = ""
    # 找元素
    # 一级窗口
    dialog  = win32gui.FindWondow("#32770",title)
    comboboxex32 = win32gui.FindWondowEx(dialog,0,"ComboBoxEx32",None) # 二级
    ComboBox = win32gui.FindWondowEx(comboboxex32,0,"ComboBox",None) # 三级
    # 编辑控件 四级
    edit= win32gui.FindWondowEx(ComboBox,0,"Edit",None)
    # 打开按钮
    button = win32gui.FindWondowEx(dialog,0,"Button","打开(&0)")
    # 发送文件路径
    win32gui.SendMessage(edit,win32con.WM_SETTEXT,None,filepath)
    # 点击打开按钮
    win32gui.SendMessage(dialog,win32con.WM_COMMAND,1,button)

time.sleep(2)
upload("d/asd")

# todo 2/16
# 优化框架  写用例
# 用例多/维护遇到的问题
# 稳定的功能 自动化 比较依赖页面  应用在回归和冒烟  重复执行的用例
# 回归 接口自动化(快速) + UI测试(正向+部分逆向场景)
# 可扩展性/可维护性/可回溯性 用例执行失败有日志什么的 复现
# 分析业务\项目状态\功能\核心业务\迭代周期
# 那些功能自动化
# 设计思想/框架
#  稳定性很重要 调试 用例通过率 脚本的bug 重试机制 Jenkins-持续集成
# 执行自动化用例 定时执行 执行频率
# 自动化测试环境 集成测试环境 预发布环境 生产环境  执行场景 冒烟  回归
# 测试报告
# 维护阶段 增加用例 优化脚本 提高稳定性  优化执行时间 修改用例、代码
# todo 2/17
# 测试数据明确 预期结果与实际结果的断言
# 图片比对 airtest
# pageobject 页面类 有元素定位属性 和操作元素方法
# 用例中直接调用页面操作 业务逻辑(+测试数据)
# 通过打断点 解决调试问题 调试技巧 哪里有问题 哪里打断点
# 定位快速消失的元素  在sources中点击暂停执行
# 用例的独立性 稳定性 重要 再考虑效率   用setup前置
# 元素地位 操作  测试用例 业务逻辑 测试数据
# 测试环境先配置好
# 场景流程自动化测试  每一个场景为一个用例
# todo 2/19
# 自动化用例设计原则 重复、繁琐的用例 冒烟和回归测试 数据清理
# 自动化测试框架
# 日志 记录用例执行过程  失败截图  用例执行不通过 截图当前页面   测试报告
# basepage 对webdriver进行二次封装 selenium webdriver api

2.10 星期三

# todo 2/6
# 定位选中可以会变化的元素要注意
# 悬浮隐藏元素 右键  检查
# 页面跑不过代码  需要等待
# sleep 辅助作用
# 窗口切换
# 窗口句柄
wins = driver.window_handles
# 切换新窗口
driver.switch_to.window(wins[-1])
# 当前窗口句柄
driver.current_window_handle
# iframe 是标签对   为什么
# 切换iframe
driver.switch_to.frame()
# 切换方式
# Switches focus to the specified frame, by index, name, or webelement.
# name属性
driver.switch_to.frame('frame_name')  # 常用
driver.switch_to.frame(1)
driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0])
# 回到默认HTML
driver.switch_to.default_content()
# 回到上一级iframe
driver.switch_to.parent_frame()
# 什么情况切换 窗口 iframe

# 切换alert弹框
alert = driver.switch_to.alert
alert.text
alert.dismiss()
alert.accept()
alert.send_keys()
# 打开网页有弹窗怎么办
# actionchains 鼠标操作 动作链
# webelement对象  locator元素定位
# 悬浮 mover
from selenium.webdriver.common.action_chains import ActionChains
# 将执行鼠标动作先放到一个列表当中,perfect() 执行鼠标动作
# todo 2/07
# 实例化
ac = ActionChains(driver)
ac.move_to_element(element).perform()
# 双击 拖拽
# Select类处理  下拉框处理
Select(element).select_by_visible_text()
Select(element).select_by_index()
Select(element).select_by_value()
# 键盘操作 特殊键
from selenium.webdriver.common.keys import Keys
element.send_keys("asda",Keys.ENTER)
# todo 2/08
# Alert类  actionchains select keys类
# 滚动条  元素顶端与窗口顶部对齐 上面
driver.execute_script(script="arguments[0].scrollIntoView();",element)  # arguents 接收外部的参数
# arguments[0].scrollIntoView(false)  元素底部与窗口底部对齐
# 移动到页面底部  “window.scrollTo(0,document.body.scrollHeight)”
# 移动到页面顶部  “window.scrollTo(document.body.scrollHeight,0)”
# 日期框操作
pha_js = "var a =argument[0];a.readonly=false;a.value= '2021/2/8'"
driver.execute_script(pha_js,element)

2.5.2021 星期五

# todo 2/3
# 窗口最大化
driver.maximize_window()
# 回到上一个页面
driver.back()
# 前进到下一个页面
driver.forward()
# 刷新
driver.refresh()
# 强制等待
time.sleep(2)
# 关闭当前窗口
driver.close()
# 退出会话 关闭浏览器 关闭Chromedriver进程
driver.quit()
# 页面组成 HTML页面内容+CSS内容呈现,布局设置,字体大小颜色+javascript
# 元素=标签 = 内容
# 调用属性
# id --在这个页面绝对唯一
# class
# style -css 外部  内部
# name
# 图片  上传文件
# 表格toble th  列表ul li 下拉列表select
# iframe
# 链接 a
# 图片 img
# input
# textarea 富文本
# alert弹窗
# 八大元素定位方法
# 只根据元素的一个属性  id name class_name tag_name
# a元素 link_text partial_link_text
# 多个属性组合或关系
# xpath css_selector
# webelement 对象
# id
element = driver.find_element_by_id()
element.is_selected()
element.find_element_by_id()
# class
driver.find_element_by_class_name()
driver.find_elements_by_class_name()
# name
driver.find_elements_by_class_name()
# tag
driver.find_element_by_tag_name("input")
# link_text
driver.find_element_by_link_text("地图")
driver.find_element_by_partial_link_text("地")
# send_keys
element.send_keys("xiaoyu")
# xpath--用的多 处理方案多一点 测试
# 绝对定位 继承顺序、兄弟位置顺序 /../../
# 相对定位 F12 critical+F
# / 父子关系 // 后代关系
# //标签名[@属性名=“属性值”]//二级元素
# CSS_selector
# todo 2/5
# //*
# 文本匹配 //a[text()="公告"]
# 包含 //标签[contains(@属性,text(),值)]
#  逻辑 组合 and or
# //标签[@属性=值 and @属性=值]
# 轴运算: 关系
# 通过同级找  通过后代元素定位表达式
# 已定位元素/轴元素::需要定位元素
# //p[@title="写亿"]/preceding-sibling::p[@class="stuno"] 当前节点之前的兄弟节点
# ancestor 祖先节点 parent父节点 following-sibling  后面的节点
# 下标/js 标签名[4]
driver.find_element_by_css_selector("input#class.id")
driver.find_element(By.XPATH, "p[@yu=‘dasd’]")
# 输入操作
driver.find_element(By.ID, "sDA").send_keys("ADS")
# 点击操作
element.click()
# 强制等待
time.sleep(3)
# 隐式等待
driver.implicitly_wait(10)  # timeoutexception nosuchelementexption
# 显示等待
from selenium.webdriver.support.wait import WebDriverWait  # 等待
from selenium.webdriver.support import expected_conditions as EC  # 判断条件

loc = (By.XPATH, "//p[@sda=‘asd’]")
WebDriverWait(driver, 15, 0.5).until(EC.visibility_of_element_located(loc))  # 元素可见
# locator 元素定位

2.2.2021 星期二

# todo 1/30
# 分时天月 星期几    * ,  -,/
# mock  模拟测试数据
res = Mock(return_value=7)
# mock 服务  JavaScript mock服务  java mock
# postman 注册mock 服务
# todo 1/31
# 个人简介
# 简历技能  突出优势()  精简  每行字数15字以内 精通 熟悉 掌握 了解
# 工作经历  负责内容 成就  自动化项目 突出自动化内容和细节
# 项目经验  re正则匹配  用例关联
# 自我评价  团队 沟通 开朗  学习能力
# todo 2/1
# 接口参数 动态参数 增加扩展性  接口依赖 Context property  重点
# 验证码接口一般不会遇到  全球鹰
# 接口文档 开发确认
# postman 和代码进行接口测试区别
# postman 不好管理和维护 拓展性不强 数据库校验 自动断言 需要插件 会javascrip  是一个封闭的系统
# 接口独立性 接口依赖
# 测试用例的设计
# 第三方框架的区别 要懂原理
# middleware 中间件 项目相关的

# todo 2/2
# 接口自动化和web自动化的区别 处理数据 和 web自动化 用户接口
# web自动化  重复点点点的就不用手了就用代码就行了
# 代码selenium 中间件 Chromedriver  浏览器 ie/Firefox/chrome
# webdirver 库   pip install -U selenium
# grid 分布式
# seleniium 工作原理  webdriver api都是一个http通信接口  通信协议jsonwireprotocol
# 通信流程  发送http请求给driver
# driver驱动浏览器
# driver返回结果给代码
from selenium import webdriver

# 启动Chromedriver 建立连接  会话ID 打开浏览器
# 与第三方的资料建立连接 需要异常处理
driver = webdriver.Chrome()
# selenium 原理 源码解析
# 打开百度
driver.get("https://www.baidu.com/")
# 代码 -http通信(json格式) - xxxdriver(驱动程序)-浏览器
# 每一个对网页的操作都是一个接口  json格式

1.26.2021 星期二

# todo 1/25
# jenkins  自动化测试  配置jdk
# 新建任务 新增项目
# todo 1/26
# jenkins windows 批处理
# 文件放在workspace
# 发送邮件
# 开启stmp服务
# 定时构建

python 接口自动化

common 公共方法

config_handler.py

读取配置文件

from configparser import ConfigParser

class ConfigHandler(ConfigParser):
    def __init__(self, file, encoding="utf-8"):
        super().__init__()
        self.read(file, encoding=encoding)

if __name__ == '__main__':
    config = ConfigHandler(file)
    config.get(
        section=section,
        option=option
    )

db_handler.py

读取数据库

import pymysql
from pymysql.cursors import DictCursor
from api_unittest_excel.common.yaml_handler import yaml_data

class DBHandler:
    def __init__(self, host, port, user, password, database,
                 charset=None, cursorclass=DictCursor, **kwargs):
        """初始化"""
        self.conn = pymysql.connect(host=host,
                                    port=port,
                                    user=user,
                                    password=password,
                                    database=database,
                                    charset=charset,
                                    cursorclass=cursorclass,
                                    **kwargs)  # 返回字典数据
        self.cursor = self.conn.cursor()

    def query(self, sql, args=None, one=True):
        self.cursor.execute(sql, args=args)
        # 事务提交
        self.conn.commit()
        if one:
            return self.cursor.fetchone()
        else:
            return self.cursor.fetchall()

    def close(self):
        self.cursor.close()
        self.conn.close()


db = DBHandler(yaml_data["database"]["host"],
               yaml_data["database"]["port"],
               yaml_data["database"]["user"],
               yaml_data["database"]["password"],
               yaml_data["database"]["database"],
               yaml_data["database"]["charset"])

excel_handler.py

读取excel表格

from openpyxl import load_workbook
from openpyxl.worksheet.worksheet import Worksheet
from api_unittest_excel.config.setting import config

class ExcelHandler:
    """操作Excel表格"""

    def __init__(self, file):
        """初始化文件名"""
        self.file = file

    def open_sheet(self, sheet_name) -> Worksheet:  # 函数的返回时worksheet 函数注解
        """打开表单"""
        wb = load_workbook(self.file)
        sheet = wb[sheet_name]
        wb.close()
        return sheet

    def read_hander(self, sheet_name):
        """读取表头数据"""
        sheet = self.open_sheet(sheet_name)
        hander_data = sheet[1]
        hander_list_data = []
        for cell in hander_data:
            hander_list_data.append(cell.value)
        return hander_list_data

    def read_excel(self, sheet_name):
        """读取所有的数据"""
        sheet = self.open_sheet(sheet_name)
        rows = list(sheet.rows)
        data = []
        for row in rows[1:]:
            row_data = []
            for cell in row:
                row_data.append(cell.value)
            dict_data = dict(zip(self.read_hander(sheet_name), row_data))  # zip用法 字典标题和数据一一对应  dict 字典转换
            data.append(dict_data)
        return data

    @staticmethod
    def write_excel(file, sheet_name, row, column, data):
        """写入Excel数据"""
        wb = load_workbook(file)
        sheet = wb[sheet_name]
        sheet.cell(row, column).value = data
        wb.save(file)
        wb.close()


excel = ExcelHandler(config.data_path)

logger_handler.py

from logging import Logger, Formatter, FileHandler, StreamHandler
from api_unittest_excel.common.yaml_handler import yaml_data

class LoggerHandler(Logger):

    def __init__(self, name="root", level="DEBUG", fmt='%(asctime)s  %(filename)s : %(levelname)s  %(message)s',
                 file=None):
        super().__init__(name)
        self.setLevel(level)
        fmt = Formatter(fmt)
        if file:
            file_handler = FileHandler(file, encoding="utf-8")
            file_handler.setLevel(level)
            file_handler.setFormatter(fmt)
            # 添加handler处理器
            self.addHandler(file_handler)
        stream_handler = StreamHandler()
        stream_handler.setLevel(level)
        stream_handler.setFormatter(fmt)
        self.addHandler(stream_handler)


logger = LoggerHandler(yaml_data["logger"]["name"],
                       level=yaml_data["logger"]["level"],
                       file=yaml_data["logger"]["file"])

# request_handler.py
import requests


class RequestHandler:
    def __init__(self):
        self.session = requests.Session()

    def visit(self, method, url, params=None, data=None, json=None, headers=None, **kwargs):
        res = self.session.request(method, url, params=params, data=data, json=json, headers=headers, **kwargs)
        try:
            return res.json()
        except ValueError:
            print("not json")

    def close(self):
        self.session.close()
# yaml_handler.py
import yaml
from api_unittest_excel.config.setting import config


class YamlHandler:
    def __init__(self, file):
        self.file = file

    def read(self, encoding="utf-8"):
        with open(file=self.file, encoding=encoding) as f:
            data = yaml.load(f, Loader=yaml.FullLoader)
        return data


yaml_data = YamlHandler(config.config_yaml_path).read()

config

logger:
  name: xiaoyu
  level: WARNING
  file: log.txt

database:
  host: "120.28.25"
  port: 111
  user: "fut2"
  password: "123456"
  database: "fut2l2n"
  charset: "utf8"

user:
  mobile_phone: "137122234"
  pwd: "1234278"

setting.py

import os


class Config:
    # 项目路径
    root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 测试数据路径
    data_path = os.path.join(root_path, "test_data/test_cases.xlsx")

    # 测试用例路径
    test_cases_path = os.path.join(root_path, "test_cases")

    # 测试报告路径
    reports_path = os.path.join(root_path, "reports")

    # 配置文件yaml路径
    config_yaml_path = os.path.join(root_path, "config", "config.yaml")


class DevConfig(Config):
    # 域名
    host = "http://120.78.128.25:8766/futureloan"


config = DevConfig()

lib

testrunner
ddt

 if isinstance(v, dict):
   test_name = mk_test_name(name, v["case_name"], i)

midderware

helper.py
import re
from jsonpath import jsonpath
from api_unittest_excel.common.db_handler import db
from api_unittest_excel.common.request_handler import RequestHandler
from api_unittest_excel.common.yaml_handler import yaml_data
from api_unittest_excel.config.setting import config
import random


def generate_mobile_phone():
    """生成一个手机号码"""
    phone_number = "1" + random.choice(["3", "5", "7", "8", "9"])
    for i in range(9):
        num = random.randint(1, 9)
        phone_number += str(num)
    return phone_number


# 登录成功
def login():
    req = RequestHandler()
    res = req.visit("post",
                    config.host + "member/login",
                    json=yaml_data["user"],
                    headers={"X-Lemonban-Media-Type": "Lemonban.v2"})
    return res


# 替换字符串变量
def replace_labal(target):
    re_pattern = r"#(.*?)#"
    while re.findall(re_pattern, target):
        key = re.search(re_pattern, target).group(1)  # 获取一个#***# 变成***
        target = re.sub(re_pattern, str(getattr(Context(), key)), target, 1)  # getattr 获取动态变量类属性  替换字符串
    return target


class Context:
    """保存临时变量"""

    # 获取load_id
    @property  # 实例属性
    def load_id(self):
        loan = db.query("select * from loan where status=2 limit 100;")
        db.close()
        return loan["id"]

    # 获取token
    @property
    def token(self):
        """保存token和member_id信息"""
        json_data = login()
        token = jsonpath(json_data, "$..token")[0]
        token_type = jsonpath(json_data, "$..token_type")
        t = " ".join([token_type, token])  # 传入列表
        return token

    # 获取member_id
    @property
    def member_id(self):
        json_data = login()
        member_id = jsonpath(json_data, "$..id")[0]
        return member_id


if __name__ == '__main__':
    print(Context().token)
## qcd_db_handler.py
from api_unittest_excel.common.yaml_handler import yaml_data


class MyDBHandler(DBHandler):

    def __init__(self):
        super(MyDBHandler, self).__init__(yaml_data["database"]["host"],
                                          yaml_data["database"]["port"],
                                          yaml_data["database"]["user"],
                                          yaml_data["database"]["password"],
                                          yaml_data["database"]["database"],
                                          yaml_data["database"]["charset"])
# 带参数的初始化
## qcd_logger.py
from api_unittest_excel.common.logger_handler import LoggerHandler
from api_unittest_excel.common.yaml_handler import yaml_data


class MyLogger(LoggerHandler):
    def __init__(self):
        super().__init__(yaml_data["logger"]["name"],
                         level=yaml_data["logger"]["level"],
                         file=yaml_data["logger"]["file"])

# 初始化
logger = MyLogger()

##reports

test_cases

test_01_register.py
import json
import unittest
from api_unittest_excel.common.db_handler import DBHandler, db
from api_unittest_excel.common.excel_handler import excel
from api_unittest_excel.common.helper import generate_mobile_phone
from api_unittest_excel.common.logger_handler import logger
from api_unittest_excel.common.request_handler import RequestHandler
from api_unittest_excel.common.yaml_handler import yaml_data
from api_unittest_excel.config.setting import config
from api_unittest_excel.lib.ddt import ddt, data


@ddt
class TestRegister(unittest.TestCase):
    # 读取数据
    test_datas = excel.read_excel("register")

    def setUp(self) -> None:
        self.req = RequestHandler()


    def tearDown(self) -> None:
        self.req.close()
        db.close()

    @data(*test_datas)
    def test_register(self, test_data):
        # 注册成功
        if "new_phone" in test_data["json_data"]:
            while True:
                phone = generate_mobile_phone()
                # 如果手机号码在数据库,继续生成手机号码,不在数据库,则替换
                phone2 = db.query("select * from member where mobile_phone=%s", args=[phone])
                if phone2:
                    continue
                else:
                    # 替换数据手机号码
                    test_data["json_data"] = test_data["json_data"].replace("#new_phone#", phone)
                    break
            # # 替换数据手机号码
            # test_data["json_data"] = test_data["json_data"].replace("new_phone", phone)
        #  已注册
        if "#exist_phone#" in test_data["json_data"]:
            phone = self.db.query("select mobile_phone from member")["mobile_phone"]
            test_data["json_data"] = test_data["json_data"].replace("#exist_phone#", phone)
        logger.info("*" * 80)
        logger.info("执行测试用例:{}{}".format(test_data["case_id"], test_data["case_name"]))
        # 访问接口,得到实际结果
        res = self.req.visit(test_data["method"],
                             config.host + test_data["url"],
                             headers=json.loads(test_data["headers"]),
                             json=json.loads(test_data["json_data"]))
        try:
            self.assertEqual(res["code"], test_data["excepted_result"])
            # 测试结果写入Excel
            excel.write_excel(config.data_path, "register", test_data["case_id"] + 1, 9, "pass")
        # except AssertionError as e:
        except Exception as e:
            logger.error("用例断言失败:{}".format(e))
            # 测试数据写回
            excel.write_excel(config.data_path, "register", test_data["case_id"] + 1, 9, "fail")
            # 手动抛出异常 让用例执行失败
            raise e

test_02_login.py
import json
import unittest
from api_unittest_excel.common.excel_handler import excel
from api_unittest_excel.common.request_handler import RequestHandler
from api_unittest_excel.lib.ddt import ddt, data

test_datas = excel.read_excel("login")


@ddt
class TestLogin(unittest.TestCase):
    def setUp(self) -> None:
        self.req = RequestHandler()

    def tearDown(self) -> None:
        self.req.close()

    @data(*test_datas)
    def test_login(self, test_data):
        res = self.req.visit(method=test_data.get("method"), url=test_data.get("url"),
                             headers=json.loads(test_data.get("headers")),
                             json=json.loads(test_data.get("json_data")))
        self.assertEqual(res, test_data.get("expected_result"))

#test_03_recharge.py
import json
import unittest

from api_unittest_excel.common.db_handler import DBHandler, db
from api_unittest_excel.common.excel_handler import excel
from api_unittest_excel.common.logger_handler import logger
from api_unittest_excel.common.request_handler import RequestHandler
from api_unittest_excel.common.yaml_handler import yaml_data
from api_unittest_excel.config.setting import config
from api_unittest_excel.lib.ddt import ddt, data
from api_unittest_excel.middlerware.helper import save_token, Context


@ddt
class TestRecharge(unittest.TestCase):

    def setUp(self) -> None:
        self.req = RequestHandler()
        save_token()

    def tearDown(self) -> None:
        self.req.close()
        db.close()

    test_datas = excel.read_excel("invest")

    @data(*test_datas)
    def test_recharge(self, test_data):
        token = Context.token
        member_id = Context.member_id
        # 充值之前的余额
        sql = "select * from member where id = %s;"
        member = db.query(sql, args=[member_id, ])
        before_money = member["leave_amount"]

        if "#member_id#" in test_data["json_data"]:
            test_data["json_data"] = test_data["json_data"].replace("#member_id#", member_id)

        # 错误的member_id
        if "#wrong_member_id#" in test_data["json_data"]:
            test_data["json_data"] = test_data["json_data"].replace("#wrong_member_id#", member_id + 2)

        headers = json.loads(test_data["headers"])
        headers["Authorization"] = token
        # 得到实际结果
        res = self.req.visit(method=test_data.get("method"),
                             url=config.host + test_data.get("url"),
                             headers=json.loads(test_data.get("headers")),
                             json=json.loads(test_data.get("json_data")))
        try:
            self.assertEqual(res["code"], test_data.get("expected_result"))
            logger.info("用例断言成功")
        except AssertionError as e:
            logger.error("用例断言失败:{}".format(e))
            # 测试数据写回
            excel.write_excel(config.data_path, "invest", test_data["case_id"] + 1, 9, "fail")
            # 手动抛出异常 让用例执行失败
            raise e
        if res["code"] == 0:
            # 充值金额
            money = json.loads(test_data["json_data"])["amount"]
            # 充值之后的余额
            sql = "select * from member where id = %s;"
            member = db.query(sql, args=[member_id, ])
            after_money = member["leave_amount"]
            self.assertEqual(before_money - money, after_money)
test_04_invest.py
import json
import unittest

from api_unittest_excel.common.db_handler import DBHandler
from api_unittest_excel.common.excel_handler import excel
from api_unittest_excel.common.logger_handler import logger
from api_unittest_excel.common.request_handler import RequestHandler
from api_unittest_excel.common.yaml_handler import yaml_data
from api_unittest_excel.config.setting import config
from api_unittest_excel.lib.ddt import ddt, data
from api_unittest_excel.middlerware.helper import save_token, Context, replace_labal


@ddt
class TestInvest(unittest.TestCase):

    def setUp(self) -> None:
        self.req = RequestHandler()
        self.db = DBHandler(yaml_data["database"]["host"],
                            yaml_data["database"]["port"],
                            yaml_data["database"]["user"],
                            yaml_data["database"]["password"],
                            yaml_data["database"]["database"],
                            yaml_data["database"]["charset"])

        # 添加项目  获取项目id
        # 审核通过  是项目为可投资项目
        # save_load_id

    def tearDown(self) -> None:
        self.req.close()
        self.db.close()

    test_datas = excel.read_excel("recharge")

    @data(*test_datas)
    def test_invest(self, test_data):
        token = Context().token
        member_id = Context().member_id
        loan_id = Context().load_id
        # 充值之前的余额
        sql = "select * from member where id = %s;"
        member = self.db.query(sql, args=[member_id, ])
        before_money = member["leave_amount"]

        test_data["json_data"] = replace_labal(test_data["json_data"])

        headers = json.loads(test_data["headers"])
        headers["Authorization"] = token
        # 得到实际结果
        res = self.req.visit(method=test_data.get("method"),
                             url=config.host + test_data.get("url"),
                             headers=json.loads(test_data.get("headers")),
                             json=json.loads(test_data.get("json_data")))
        try:
            self.assertEqual(res["code"], test_data.get("expected_result"))
            logger.info("用例断言成功")
        except AssertionError as e:
            logger.error("用例断言失败:{}".format(e))
            # 测试数据写回
            excel.write_excel(config.data_path, "register", test_data["case_id"] + 1, 9, "fail")
            # 手动抛出异常 让用例执行失败
            raise e
        if res["code"] == 0:
            # 充值金额
            money = json.loads(test_data["json_data"])["amount"]
            # 充值之后的余额
            sql = "select * from member where id = %s;"
            member = self.db.query(sql, args=[member_id, ])
            after_money = member["leave_amount"]
            self.assertEqual(before_money + money, after_money)

# test_add.py
import json
import unittest
from api_unittest_excel.common.excel_handler import excel
from api_unittest_excel.common.request_handler import RequestHandler
from api_unittest_excel.config.setting import config
from api_unittest_excel.lib.ddt import ddt, data
from api_unittest_excel.middlerware.helper import replace_labal, Context
from api_unittest_excel.middlerware.qcd_db_handler import MyDBHandler
from api_unittest_excel.middlerware.qcd_logger import logger


@ddt
class TestAdd(unittest.TestCase):
    # 读取数据
    test_datas = excel.read_excel("add")

    def setUp(self) -> None:
        self.req = RequestHandler()
        self.db = MyDBHandler()

    def tearDown(self) -> None:
        self.req.close()
        self.db.close()

    @data(*test_datas)
    def test_add(self, test_data):
        # 用的admin token
        token = Context().token
        headers = json.loads(test_data["headers"])
        headers["Authorization"] = token
        test_data["json_data"] = replace_labal(test_data["json_data"])
        logger.info("*" * 80)
        logger.info("执行测试用例:{}{}".format(test_data["case_id"], test_data["case_name"]))
        # 访问接口,得到实际结果
        res = self.req.visit(test_data["method"],
                             config.host + test_data["url"],
                             headers=headers,
                             json = json.loads(test_data["json_data"]))
        try:
            self.assertEqual(res["code"], test_data["excepted_result"])
            # 测试结果写入Excel
            excel.write_excel(config.data_path, "register", test_data["case_id"] + 1, 9, "pass")
        # except AssertionError as e:
        except Exception as e:
            logger.error("用例断言失败:{}".format(e))
            # 测试数据写回
            excel.write_excel(config.data_path, "register", test_data["case_id"] + 1, 9, "fail")
            # 手动抛出异常 让用例执行失败
            raise e


test_data

readme

run_cases_test.py

import os
import time
import unittest
import datetime
# 项目路径
from TestRunner import HTMLTestRunner

from api_unittest_excel.config.setting import config

# dir_path = os.path.dirname(os.path.abspath(__file__))
# # 测试用例文件路径
# test_cases_path = os.path.join(dir_path, "test_cases")
# 自动找test开头的模块  已创建对象
suite = unittest.defaultTestLoader.discover(config.test_cases_path, "test_*.py")
# 生成时间挫
# fmt = str(int(time.time()))
# fmt = time.strftime('%Y-%m-%d%H:%M:%S',time.localtime(time.time()))
time_stamp = '{0:%Y%m%d%H%M%S}'.format(datetime.datetime.now())
report_name = "report{}.html".format(time_stamp)
report_name_path = os.path.join(config.reports_path, report_name)
# if not os.path.exists(report_name_path):
    # os.mkfifo(report_name_path)
with open(report_name_path, "wb") as file: # 二进制形式
    # 运行用例  生成HTML文本测试报告
    runner = HTMLTestRunner(stream=file, verbosity=2, title="xiaoyu测试报告", description="用例")
    runner.run(suite)

1.24.2021 星期天

# 动态数据获取
# TODO 1/23
# 动态数据  例如 注册超过的手机号码  可以随机生成和数据库对比  维护代码
# 接口依赖
# 充值接口
# TODO middleware 中间件  helper。py
# jsonpath  解析json数据  提取
# $ 根节点 .子节点  ..所有节点
# $..token
token = jsonpath(data, "$..token")[0]  # 在一个列表中 获取token
# getattr 使用
# TODO 1/24
# context  用类属性的方法存储临时变量
#  提交事务  数据同步的作用
self.conn.commit()
# Context 环境管理方式
# 投资模块
# 断言 接口返回  和 其他的校验 余额是否正确  看用例
# 添加项目和审核项目
# setattr
# Excel 表格 多个参数动态变换  用正则表达式
# 正则表达式  调用的字符串匹配技术
# python 匹配方式  re模块  正则表达式在线
# 匹配
import re

# 匹配的字符串 连续的
pattern = r"abc"
a = "abcdwalsdasldabcalsjkdacblaskdabcssssdasd"
# 从开始的位置匹配
res = re.match(pattern, a)
print(res)
# 全文匹配
re.search(pattern, a)
print(res)
# 全部匹配
re.findall(pattern, a)
print(res)
# 【abc 】[a-c]  匹配【】中任意其中一个字符
pattern = r"[abc]"
re.findall(pattern, a)
# r"."  匹配任意的一个字符串,除了\n
pattern = r"."
re.findall(pattern, a)  # 返回的是列表
# \d 匹配任意一个数字字符等价于[0-9] data
pattern = r"\d"
# \D 匹配非数字字符
# \w 匹配数字、字母、下划线 等价于[A-Za-z0-9_]
# \W 匹配非数字、字母、下划线 等价于[^A-Za-z0-9_]
# r"\w{2}" 匹配两个连续\w  {2}
# r"\w{2,}" 匹配至少两个连续\w
# 贪婪模式 python 默认 正则表达式
# {中打空格什么意思}
# r"\w{,2}" 匹配最多两个连续\w  0,1,2
# r"\w{2,4}" 匹配2-4次连续\w
# 匹配一个手机号码
r"1[35789]\d{9}"
# 邮箱号码
# * 匹配数字0次或任意次,通配符 常用 比如discover 中匹配test_*.py
r"\d*"
# + 匹配一次或任意次
r"\d+"
# 组合 r"\d." 匹配连续的数字和任意字符(除了\n)
# ?匹配为非贪婪模式
r"\d?"  # 匹配0次或1次
# r"\d*?"
# ^ 开头
r"^\d"  # 匹配开头
r"\d$"  # 匹配结尾
r"\d*$"  # 匹配结尾任意多次
# 匹配任意字符任意次 非贪婪模式
r"#.*?#"  r"#.+?"  # 匹配至少一次
r"#(.*?)#"  # 组去掉#号
re.search()
# 替换操作
re.sub(pattern, repl=repl, string=strring, 1)


# todo 正则表达式替换字符串封装
def replace_labal(target):
    re_pattern = r"#(.*?)#"
    while re.findall(re_pattern, target):
        key = re.search(re_pattern, target).group(1)  # 获取一个#***# 变成***
        target = re.sub(pattern, str(getattr(Context(), key)), target, 1)  # getattr 获取动态变量类属性  替换字符串
    return target
#jenkins  持续集成CI
# xml 百度搜索

1.22.2021星期五

# TODO 1/22
# __str__
# 动态数据  使脚本复用性强
# python操作数据库
import pymysql

# 建立连接实例化
conn = pymysql.connect(host="120.78.128.25", port=3306, user=future, password=password, charset="utf8",
                       database=futureloan,cursorclass=DictCursor)  # 查询sql后返回的字典
# 游标 实例化游标
cursor = conn.cursor()
# 执行sql
cursor.execute("select * from member where mobile_phone=%s;",args=[mobile,]) #向sql传入参数 防止sql注入
# 获取查询sql后的数据  游标结果,光标
cursor.fetchone()
cursor.fetchall()  # 默认返回元组包元祖
# 操作数据库  游标保持独立性
cursor.close()
conn.close()
# 关闭游标
# TODO 封装pymysql
import pymysql
from pymysql.cursors import DictCursor


class DBHandler:
    def __init__(self, host, port, user, password, database,
                 charset=None, cursorclass=DictCursor, **kwargs):
        """初始化"""
        self.conn = pymysql.connect(host=host,
                                    port=port,
                                    user=user,
                                    password=password,
                                    database=database,
                                    charset=charset,
                                    cursorclass=cursorclass,
                                    **kwargs)  # 返回字典数据
        self.cursor = self.conn.cursor()

    def query(self, sql, args=None, one=True):
        self.cursor.execute(sql, args=args)
        if one:
            return self.cursor.fetchone()
        else:
            return self.cursor.fetchall()

    def close(self):
        self.cursor.close()
        self.conn.close()

1.20.2021星期三

# json和字典的转换
json.loads() # json加载为python字典  json用双引号 null Nonez转换
json.dumps()   # 字典转换为json
# json.decoder.JSONDecodeError: Extra data: line 1 column 24 (char 23)
# 在Excel表格中json数据没加{}
# 整体架构和框架
#动态数据处理
# 测试用例关联
# 正则表达式
# 数据库状态查看
# 框架的分层
# run_test.py:作用:代码人口,收集测试用例,生成测试报告
# test_cases 测试逻辑 各个模块的测试用例方法:便于管理
# 数据管理层 test_data  Excel 表格管理
# 业务逻辑层 通用的  common
# 配置文件  (config 一些常量 例如地址什么的)
# 输出  reports 测试报告  日志文件
# python 配置文件  一般是程序动态获取的
# yaml 配置文件  一般是常量  写死的
# INI 老配置文件

python程序报错

# json.decoder.JSONDecodeError: Extra data: line 1 column 24 (char 23)
# JSON解码错误:额外的的数据  json.loads(json数据)
# 在Excel表格中json数据没加{}

1.18.2021星期一

# TODO 1/17/2021
# TODO 修改ddt源码
if isinstance(v, dict):  # 用于函数封装修改,复制修改文件  类和对象是用继承重写就可以修改
    test_name = mk_test_name(name, v["case_name"], i)
# log日志  记录信息便于定位问题  logging
# 日志级别
# 日志收集器 级别 处理器handler 处理器级别设置 设置日志格式format 添加日志处理器
logger = logging.getLogger("xiaoyu")  # 笔记本
# 设置级别
logger.setLevel("DEBUG")
# 设置日志格式format
fmt = logging.Formatter("日志格式")
# 放到file文件中处理器handler  笔写在文件里
file_handler = logging.FileHandler("file.txt")
file_handler.setLevel("DEBUG")
file_handler.setFormatter(fmt)
# 添加handler
logger.addHandler(file_handler)
logger.info('hello')
# TODO logger 封装 继承重写logger
from logging import Logger, Formatter, FileHandler, StreamHandler


class LoggerHandler(Logger):

    def __init__(self, name="root", level="DEBUG", fmt='%(asctime)s  %(filename)s : %(levelname)s  %(message)s',
                 file=None):
        super().__init__(name)
        self.setLevel(level)
        fmt = Formatter(fmt)
        if file:
            file_handler = FileHandler(file)
            file_handler.setLevel(level)
            file_handler.setFormatter(fmt)
            # 添加handler处理器
            self.addHandler(file_handler)
        stream_handler = StreamHandler()
        stream_handler.setLevel(level)
        stream_handler.setFormatter(fmt)
        self.addHandler(stream_handler)


logger = LoggerHandler(file="log.txt")


# 配置文件
# 放入常量
# python模块
class Config:
    level = "DEBUG"


# yaml文件 语法  pip install pyyaml
import yaml

# 读取文件
with open("w.yaml", encoding="utf-8") as f:
    data = yaml.load(f.read(), Loader=yaml.FullLoader)  # 文件流
# ini 文件  conf文件
config = ConfigParser()
# 读取文件
config.read("w.ini",encoding="utf-8")
a = config.get("tea","name")  # section  option
# sys模块
sys.platform
# TODO 1/18
# config 封装 读取ini
from configparser import ConfigParser


class ConfigHandler(ConfigParser):
    def __init__(self, file, encoding="utf-8"):
        super().__init__()
        self.read(file, encoding=encoding)

if __name__ == '__main__':
    config = ConfigHandler(file)
    config.get(
        section=section,
        option=option
    )
    # 修改文件
    config["teacher"]["option"] = "xiaoyu"
with open("f.ini",mode="a",encoding="utf-8") as f:
    config.write(f)
# IO文件处理
open()
# 文件流 stream
open().read())
# 写入yaml文件
with open("file.yaml",mode="w",encoding="utf-8") as f:
    yaml.dump(data,stream=f,allow_unicode = True)

# 什么样的功能或项目适合做自动化测试
# 测试流程

1.16.2021 星期六

# TODO  2021/1/16
# 读取excel表格  读之前要关闭文件
wb = openpyxl.load_workbook(r"文件路径")
wb._sheets  # 私有属性  sheet对象
# 创建sheet 激活
wb.active
wb.sheetnames  # 列表存储sheet名字
sheet = wb.worksheets[0]  # sheet 对象
# 通过名字获取sheet 对象
sheet1 = wb["sheetname"]
# 获取单元格对象
cell = sheet.cell(1, 2)
# 获取单元格值
cell.value
# 获取行、列
sheet[1]
sheet["A"]
# 获取多行 sheet[1:3]  1-3 行
# 获取所有数据
data = list(sheet.rows)
for row in data:
    for cell in row:
        print(cell.value)
# 保存Excel
wb.save(r"文件名称")
# 关闭
wb.close()

# TODO openpyxl excel 封装
from openpyxl import load_workbook
from openpyxl.worksheet.worksheet import Worksheet


class ExcelHandler:
    """操作Excel表格"""

    def __init__(self, file):
        """初始化文件名"""
        self.file = file

    def open_sheet(self, sheet_name) -> Worksheet:  # 函数的返回时worksheet 函数注解
        """打开表单"""
        wb = load_workbook(self.file)
        sheet = wb[sheet_name]
        wb.close()
        return sheet

    def read_hander(self, sheet_name):
        """读取表头数据"""
        sheet = self.open_sheet(sheet_name)
        hander_data = sheet[1]
        hander_list_data = []
        for cell in hander_data:
            hander_list_data.append(cell.value)
        return hander_list_data

    def read_excel(self, sheet_name):
        """读取所有的数据"""
        sheet = self.open_sheet(sheet_name)
        rows = list(sheet.rows)
        data = []
        for row in rows[1:]:
            row_data = []
            for cell in row:
                row_data.append(cell.value)
            dict_data = dict(zip(self.read_hander(sheet_name), row_data))  # zip用法 字典标题和数据一一对应  dict 字典转换
            data.append(dict_data)
        return data

    @staticmethod
    def write_excel(file, sheet_name, row, column, data):
        """写入Excel数据"""
        wb = load_workbook(file)
        sheet = wb[sheet_name]
        sheet.cell(row, column).value = data
        wb.save(file)
        wb.close()


# TODO test_login.py  测试用例模块
# ddt -->data driver testing  pip install ddt 是unittest的一个插件  数据驱动思想
# python/unittest/ddt 测试框架
@ddt.ddt  # 作用
class Testlogin(unittest.TestCase):
    def setUp(self) -> None:
        pass

    def tearDown(self) -> None:
        pass

    @ddt.data(*test_datas)  # 传入列表数据[{},{}]
    def test_login(self, test_data):  # 传入字典数据
        self.assertEqual(res, test_data["expected_result"])

1.15.2021 星期五

# 加载指定模块  指定类
from HTMLTestRunner.HTMLTestRunner import HTMLTestRunner

suite = unittest.defaultTestLoader.loadTestsFromModule(test_login)
# 加载多个模块
suite_totle = unittest.makeSuite()
suite_totle.addTests(suite)
suite_totle.addTests(suite1)
# 生成HTML测试报告  HTMLTestRunnerNew库  可以放到site-pakage  公共库
# TODO 生成HTML报告
import os
import time
import unittest
import datetime
# 项目路径
from TestRunner import HTMLTestRunner


dir_path = os.path.dirname(os.path.abspath(__file__))
# 测试用例文件路径
test_cases_path = os.path.join(dir_path, "test_cases")
# 自动找test开头的模块  已创建对象
suite = unittest.defaultTestLoader.discover(test_cases_path, "test_*.py")
# 生成时间挫
fmt = str(int(time.time()))
# fmt = time.strftime('%Y-%m-%d%H:%M:%S',time.localtime(time.time()))
time_stamp = '{0:%Y%m%d%H%M%S}'.format(datetime.datetime.now())
report_name = "report{}.html".format(time_stamp)
report_name_path = os.path.join(dir_path, "reports", report_name)
# if not os.path.exists(report_name_path):
    # os.mkfifo(report_name_path)
with open(report_name_path, "wb") as file: # 二进制形式
    # 运行用例  生成HTML文本测试报告
    runner = HTMLTestRunner(stream=file, verbosity=2, title="xiaoyu测试报告", description="用例")
    runner.run(suite)

1.14.2021 星期四

# 先执行setup,然后执行test用例,最后执行teardown
# Todo 执行测试用例 生成报告 run_test
import os
import unittest

# 查找、加载测试用例
dir_path = os.path.dirname(os.path.abspath(__file__))
test_cases_path = os.path.join(dir_path, "test_cases")
# 自动找test开头的模块  已创建对象
suite = unittest.defaultTestLoader.discover(test_cases_path, "test_*.py")
report_name = os.path.join(dir_path, "reports", "report1")
if not os.path.exists(report_name):
    os.mkfifo(report_name)
with open(report_name, "w", encoding="utf8") as file:
    # 运行用例  生成普通文本测试报告
    runner = unittest.TextTestRunner(file, verbosity=2)
    runner.run(suite)

# m是函数、方法  c是类 v是变量

1.13.2021 星期三

# TODO 2021/1/13
# TODO requests封装
class RequestHandler:
    def __init__(self):
        self.session = requests.Session()

    def visit(self, method, url, params, data, json, headers, **kwargs):
        res = self.session.request(method, url, params=params, data=data, json=json, headers=headers, **kwargs)
        try:
            return res.json()
        except ValueError:
            print("not json")

# 如果想断言失败,要抛出异常
raise AssertionError
# 断言结果  。通过 pass F false 断言失败  E error 程序内部错误
#  unittest.main()与右键unittest为什么不能同时运行
# 执行顺序  根据ASCII码 用数字来控制执行顺序
# 运行 用右键unittest 运行   在类名执行测试类,方法名执行单个测试用例  空行执行整个模块
# 命令行 运行unitest
# 断言方式
# self.assertEqual()  打印预期结果  assertTrue() 复制的表达方式 只有true
# assertIn   assertRegex 正则表达式匹配

1.12.2021 星期二

# if True
# 响应行
# 响应版本号
# 状态码   200 201 304 404 500
# 响应头  响应的数据格式 content-type
# 响应体  返回的数据
# cookie session和token的区别
# 输入url后的过程
# 三次握手四次挥手
# TODO 2021/1/12
# requests 库的使用
# get
import requests

# querystring 查询字符串的形式 放在url中
headers = {"token": "sada"}
params = {"token": "sada"}
res = requests.get(url, params=params, headers=headers)
# post  默认表单形式
from_data = {"asd": "Sdad"}
json_data = {"sda": "dsfw"}
requests.post(url=url, data=from_data, json=json_data, headers=headers)
# response 对象
res.text  # 字符串
# 二进制形式 图片、视频
res.content
# json  字典数据类型
res.json()

# 注册接口url
url = "http://120.78.128.25:8766/futureloan/member/register"
headers = {"X-Lemonban-Media-Type": "Lemonban.v1"}
json_data = {"mobile_phone": "18773181811", "pwd": "1234567"}
res = requests.post(url=url, json=json_data, headers=headers)
print(res.json())
# 登录接口
url = "http://120.78.128.25:8766/futureloan/member/login"
headers = {"X-Lemonban-Media-Type": "Lemonban.v2"}
# token 放在哪里看接口文档
# cookie  请求头  http协议
res = requests.post(url, json=json_data, headers=headers) # 请求头自动带传递数据类型
print(res.json())
# 获取登录token 用来使用其他接口
# 充值接口
url = "http://120.78.128.25:8766/futureloan/member/recharge"
token = res.json()["data"]["token_info"]["token"]
id = res.json()["data"]["id"]
headers = {"X-Lemonban-Media-Type": "Lemonban.v2", "Authorization": "Bearer{}".format(token)}
data = {
    "member_id": id,
    "amount": 100
}
res = requests.post(url,json=data,headers = headers)
print(res.json())
# cookin 用session 会话会自动保存cookin
requests.session()
# requests封装
# 单元测试框架unittest 测试visit函数 类
# 单元测试框架和接口测试有什么关系    测试访问接口函数
# 模块 test开头  类 Test开头  函数 test开头
# 运行方式unittest与pytest切换
# 断言预期结果

1.10.2021 星期日

# split 分割字符串为列表
a = "a,s,d"
a.split(",")
# 三目运算符
# time()
# isinstance
isinstance(a, str)
# [[],[],[]]转换为[{},{},{}]
cases = [[], [], []]


def transform_1():
    title = cases[0]
    new_case = []
    for case in cases[1:]:
        dict_data = {}
        for i, data in enumerate(case):
            dict_data[title[i]] = data
        new_case.append(dict_data)
    return new_case


# zip 用法 [1,2],[3,4]->[(1,3),(2,4)]
def transform_zip():
    title = cases[0]
    new_case = []
    for case in cases[1:]:
        dict_data = dict(zip(title, case))
        new_case.append(dict_data)
    return new_case


# random 内置摸快 time 直接模块名
# 模块导入  form 包名.模块名 import 类名,函数名,变量名  as r  重命名
# 模块的搜索顺序
# 打印这个模块的路径
print(__file__)
# __name__  运行当前模块名 为__main__
if __name__ == "__main__":
# python内置模块在lib\site-packages
# os模块
import os

# pwd 显示当前文件夹路径
os.getcwd()
# 获取绝对路径
os.path.abspath(__file__)
# 获取文件夹路径
a = os.path.dirname(os.path.abspath(__file__))
# 路径拼接
b = os.path.join(a, "yu.txt")
# 创建文件夹
os.mkdir(a)
os.path.isdir(a)
os.path.isfile(a)
# 路径是否存在
os.path.exists(a)
"""
os,open 的作用
自动生成报告
打开、读取文件、关闭
"""
# 编码string-->byte 解码byte-->string  encoding
# mode模式: r ,w 写,a 追加  b binary ,二进制 图片、视频 rb,wb    t 文字模式   + 又读又写
with open(b, mode="r", encoding="utf-8") as file:
    file.read()
    # 读取一行
    file.readline()
    # 读取所有行
    file.readlines()
    file.close()
# 读取机制:根据光标移动  seek()
# 异常;  常见的异常类型
# IOError:输入输出异常
try:
    pass
except IndexError as e:  # 捕获错误类型给e
    raise IndexError  # 抛出异常 程序错误 控制异常
except TypeError as e:
    pass
finally:
    # 都会执行的语句
    pass


# 类

class RenLei():
    pass


class XiaoYu(object, RenLei):  # 大驼峰式命名   继承  多重继承
    xiaoyu = "yu"  # 类属性

    def __init__(self, name):  # 初始化函数、初始化方法 只能返回None
        self.name = name  # 实例属性  self:表示实例自己,在函数里面使用

    def hello(self):  # 实例方法
        return self.name

    @staticmethod
    def chen():  # 静态方法 方便管理
        pass

    @classmethod  # 构造init
    def make_instance(cls, name):  # 类方法  cls = XiaoYu
        return cls(name)

    def __repr__(self):  # 返回对象打印出来的效果,名字固定用法
        return self.name


print(XiaoYu.xiaoyu)  # 类属性的获取
chen = XiaoYu("xiaoyu")  # 对象、实例、东西 object  具体的事物  实际调用init函数
print(chen.name)  # 获取实例属性
chen.hello()  # 获取实例方法
XiaoYu.chen()  # 静态方法的调用
XiaoYu.make_instance()  # 类方法的调用
# 格式化
f"sss{a}sdas"
# join() 用于将序列中的元素以指定的字符连接生成一个新的字符串。
str = "-"
seq = ("a", "b", "c")  # 字符串序列
str.join(seq)
# 以上实例输出结果如下:
# a-b-c
# 类里面的函数就叫方法
# 静态方法
# 类的继承 子类可以使用父类的方法、属性
# 多重继承  继承多个父类
# 菱形问题 C3算法  广度优先  A\B(A)\C(A)\D(B,C)
# 深度优先   A\B(A)\C\D(B,C)
# 查找顺序
print(XiaoYu.__mro__)
# 超继承 更新父类方法
super().call()  # 调用父类的方法
super().__init__()  #
# debug 调试 断点调试
# getattr  获取类\对象的属性值
getattr(XiaoYu, "chenyu", "xiaoyu")  # 类/对象 属性 属性默认值(没有属性值的时候)
# 设置属性 类\对象的属性值
setattr(XiaoYu, "sad", "sda")

# 接口基础
# 什么是接口 web api 是api中的一种
from flask import Flask

app = Flask(__name__)


@app.route("/login")  # 函数和地址绑在了一起
def login():
    return "登录成功"


if __name__ == '__main__':
    app.run()
# 什么是网络请求  http  websocket webservice
# http 请求协议
# 请求行 :URL  域名 DNS解析  IP地址   请求方法get head post put  delect   get和post区别
# body参数方式 content-type
# 请求头 user-agent 用户代理  content-type:请求数据格式 cookie 让无状态变有状态
# 请求体  请求数据
# 响应
# 响应行 响应头 响应体

1.9.2021 星期六

# 列表 可变、有序类型  1/9/2021
# 索引
# 切边
# 长度 len()
# 添加新的元素
import random

a = ["ren"]
a.append("asd")
# 添加多个
a.extend(["asd", "sada", "sad"])
# 指定位置添加
a.insert(0, "sadsa")
# 删除指定的值
a.remove("sad")
# 删除指定的索引,弹出
a.pop(0)
# 删除末尾的值
a.pop()
# 删除所有的元素
a.clear()
# 不用del 从内存当中直接删除
# del a
# 修改
a[0] = "sada"
# index 返回索引
a.index("asd")
# count
a.count("Sad")
# 逆序
a.reverse()
# 逆序2 重新创建变量
b = a[::-1]
# 排序 数字排序
a.sort()
# 倒排
a.sort(reverse=True)
# 字典(可变,无序),有标记 key:value  key 一般用字符串 不可变类型 唯一 分散存储
info = {"name": "xiaoyu", "age": 11}
# 获取某个元素
name = info["name"]
# 获取长度
len(info)
# 元素修改和添加
info["name"] = "sadas"
# 随机删除
info.popitem()
# 删除指定key
info.pop("name")
# 清除
info.clear()
# 获取[(key,value),(key,value)]
info.items()
# 获取key
info.keys()
# 获取values
info.values()
# 元组 tuple 不可变 有序
c = ("sada", "sda", "sada")
# 索引
# 切边
# a = (1,) 元组  a=1,2 元组 a=(1) 非元祖
# 元祖解包
a, d = 3, 4
# 集合 无序
# 去重 list(set(list))
yu = {"sada", "Dsad", "Sdad"}

# 构造函数
dict()
# 算数运算
# 浮点数运算  用Decimal函数
# 赋值运算
# 比较运算
# 逻辑运算 and or not
# 成员运算  in  not in
# 字典中in 是判断key值
# if ...elif..else:..
# python遇到冒号要缩进
# for循环 遍历
# 字典
dict_data = {"name": "xiaoyu", "age": "18"}
for i, v in dict_data.items():  # 元祖解包
    print(i, v, end="/")
# while(重点)  死循环
i = 0
while True:
    print("sad")
    if i == 999:
        print("循环结束")
        break  # 结束循环
    i += 1
    continue  # 退出这一次循环,执行下一次循环

print("结束")
# 获取随机数 1-3
random.randint(1, 3)
# 获取最大值
max(a, b, c)
# 获取1-9 用于for循环
range(1, 9)
# 99乘法表
for i in range(1, 10):
    for j in range(1, i + 1):
        print("{}*{}={}".format(j, i, i * j), end=" ")
    print()
# for 循环不要修改列表 可以新建列表复制出来 或外循环
list_data = ["1", "sad", "21"]
for we in list_data[:]:
    list_data.remove(we)
    # index+1


# 函数 存储一段可以重复执行的程序
# 遇到return 程序终止
# 函数参数 位置参数 关键字参数   默认参数   不定长参数、动态参数
def sums(a, b="a", *args, **kwargs):  # **kwargs  keyword-arguments接受多余的关键字参数
    # args 是元祖  kwargs 是字典
    pass


data = [1, 23, 4, 5]
sums(1, b="2", *data, **dict_data)  # *data 解包脱衣服  **解包字典
# 执行代码先函数先注册、定义
# 函数内局部变量  全局变量
global list_data  # 关键字 声明全局变量 会造成数据紊乱
# python内置函数  print() input() len()  max()
# range()  是一个类
# enumerate() 枚举
for index, i in enumerate([1, 3, 4, 7]):
    print(index, i)
# 查看内存地址  id() 
# eval() 脱字符串的衣服
# zip() round()
# 模块 module 就是python文件
# 包 package  python文件的文件夹 包含一个 __init__.py文件
# 查看源码方法 1、注释 2、函数名 3、参数 4、返回

1.8.2021 星期五

name = """
sadas
sadadass
sad"""

# python 数据类型  int float bool str list tuplr dict set
# pycharm debug 调试  计算器使用
# 查看数据类型  type(file)
# 数据类型的转化  int(str) str() bool() dict() list()

# 字符串 不可变类型
# r的使用 转义字符变成正常字符  file = r"d:\hshs\shsj.txt"

# 字符串的操作
# 字符串拼接 +  重复多次  *
# 获取字符串的长度
# 数据索引  索引超出范围会报错  IndexError
# 字符串切片
# 格式化
"{}{}{}{}".format(c, a, a, v)

# 复制字符串 切片复制
# 字符串内置函数
str1 = "abc"
# 获取长度
len(str1)
# 转化成大写
str1.upper()
# 转化成小写
str1.upper().lower()
# 大小写转换
str1.upper().lower().swapcase()
# 查找
str1.find("a")  # 经常使用
str1.index("q")  # ValueError  会报错
# 替换 并重新给新的对象
str2 = str1.replace("a", "s", 1)  #经常使用
# 统计
str1.count("a")
# 字符串拼接,正规方式的+
".".join([str1, str2])  # 用的比较多
# 字符串分割
str1.split("++")  #经常使用
# 去掉左右两边的指定字符串
str1.strip(" a")  #经常使用
# 去掉左边 右边
str1.lstrip("a").rstrip("c")
# 判断是否是正整数
str1.isdigit()  #经常使用

1.7.2021 星期四

# 变量 存储数据
# 字符串: 单引号 双引号 三引号:写多行字符串

1.5.2021 星期二

断言
日志

1.3.2021 星期日

import requests

url = 'http://127.0.0.1:5000/api/huace/userDelete'
# delete
res = requests.delete(url)
print(res.json())

# auto 鉴权接口
url = "http://127.0.0.1:5000/api/huace/auth"
session = requests.session()
session.auth = ("admin", "huace123456")
res = session.request("post", url)
print(res.json())
# 登录加密接口
# session会话管理 --token
url = 'http://127.0.0.1:5000/api/huace/login'
data = {
    "username": "admin",
    "password": "123456"
}
headers = {"Content-Type": 'application/json'}  # 字典
# 创建session对象
session = requests.session()
res = session.request("post", url, json=data, headers=headers)
'''获取token值,将token值写入head
1:登录接口的响应结果中获取token节点的值
2:获取token节点的值新增到head参数中去

'''
get_token = res.json()['token']
# print("登录接口token节点的值:",get_token)
# session会话去更新headers中的内容值
session.headers.update({'token': get_token})  # {'token':''huacetest''}
# 查看请求头中是否有添加
print(session.headers)

'''用户详情信息的接口'''
url2 = 'http://127.0.0.1:5000/api/huace/userList'
res2 = session.get(url2)
print(res2.text)

# httprequests 封装
import requests


class HttpClientRequest():
    def __init__(self):
        # 创建会话
        self.session = requests.session()
        self.url_pre = 'http://127.0.0.1:5000/api/huace/'

    def init_headers(self, head=None):
        self.head = {"Content-Type": 'application/json'}
        if head:
            self.session.headers.update(head)

    def SendRequest(self, method, url, **kwargs):
        self.url = self.url_pre + url
        # print(kwargs)  #{'json': {'username': 'admin', 'password': '123456'}}
        self.data = None
        if 'json' in kwargs:
            self.data = kwargs['json']  # {'username': 'admin', 'password': '123456'}
        self.res = self.session.request(method=method, url=self.url, json=self.data)
        self.response = self.res.json()

        # 提取响应结果中的值  --token:huacetest
        if 'tiqu' in kwargs:  # {'json': {'username': 'admin', 'password': '123456'}, 'tiqu': 'token'}
            self.val = kwargs['tiqu']  # 'token'
            self.get_token = self.response[self.val]

            # token:huacetest追加到请求头中去
            # self.session.headers.update({self.val:self.get_token})
            self.init_headers({self.val: self.get_token})

        return self.response

12.29.2020 星期二

import json

import requests
from jsonpath import jsonpath

url = "http://49.233.108.117:3000/api/v1"
data = {
    "page": "1",
    "tab": "share",
    "limit": 3,
    "mdrender": True
}
res = requests.get(url + "/topics", params=data)
print(res.json())  # 字典
# 对结果进行格式化处理
res_json = json.dumps(res.json(), indent=4, ensure_ascii=False)  # json格式
print(res_json)

# 接口关联
# 新建主题
json_data = {
    "accesstoken": "a4b7e66f-12d7-4543-95e7-e6e7ad821fbf",
    "title": "小小小小adsad",
    "tab": "ask",
    "content": "chenchen"
}
headers = {"Content-Type": "application/json"}
res = requests.post(url + "/topics", json=json_data, headers=headers)
print(res.json())
# 获取topic_id
topic_id = jsonpath(res.json(), "$.topic_id")[0]
print(topic_id)
# 编辑主题
json_data1 = {
    "accesstoken": "1c2922bb-5789-4abd-9f46-639a8a57ca00",
    "title": "小小小小adsad11111111",
    "topic_id": topic_id,
    "tab": "ask",
    "content": "chenchen"
}
res = requests.post(url + "/topics/update", json=json_data1, headers=headers)
print(res.json())

url1 = "http://www.testingedu.com.cn:8000/index.php?m=Home&c=User&a=do_login"
headers1 = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
    "username": 13800138006,
    "password": 123456,
    "verify_code": 1111
}
# cookie关联  用session
session = requests.session()
res = session.post(url1, data=data, headers=headers1)
print(res.json())
res = session.get("http://www.testingedu.com.cn:8000/Home/Order/order_list.html")
print(res.text)

# 文件上传
url = "http://www.testingedu.com.cn:8000/index.php/home/Uploadify/imageUp/savepath/head_pic/pictitle/banner/dir/images.html"
file = {"file": ("baidu.png", open(r"D:\文档\pythonProject\api_auto\test\baidu.png", "rb"), "image/png")}
data = {
    "name": "baidu.png"
}
res = requests.post(url, data=data, files=file)
print(res.json())

# token关联
url = "http://127.0.0.1:5000/api/huace/login"
data = {
    "username": "admin",
    "password": "123456"
}
headers = {"Content-Type": 'application/json'}
# 登录接口
res = requests.post(url, json=data, headers=headers)  
token = jsonpath(res.json(), "$.token")[0]
headers["token"] = token
# 用户详细信息接口
url = "http://127.0.0.1:5000/api/huace/userList"
res = requests.get(url, headers=headers)
print(res.text)

12.28.2020 星期一

import requests

url = "https://www.baidu.com/"
res = requests.get(url)
print(res.status_code)
print(res.text)
print(res.encoding)
# 修改响应对象的编码格式
res.encoding = "utf-8"
print(res.text)

# get请求带参数
data = {"id": 1001}
data1 = {"id": "1001,1002"}
data2 = {"id": 1001, "kw": "长沙"}
# res = requests.get(url, params=data2)
res = requests.request("get", url, params=data2)
print(res.url)
print(res.text)

import json
import requests

url = "http://api.test.zhulogic.com/designer_api/account/login_quick"
headers = {"Content-Type": "application/json"}
json_data = {
    "phone": 15100001111,
    "code": 1234,
    "unionid": "",
    "messageType": 3,
    "channel": "zhulogic"
}
print(json.dumps(json_data))  # 将字典转换为json格式
res = requests.post(url, json=json_data, headers=headers)
print(res.text, type(res.text))  # 返回字符串
print(res.json(), type(res.json()))  # 返回字典


# content 主要用于图片、视频格式
url1 = "https://www.baidu.com/img/flexible/logo/pc/result.png"
res = requests.get(url1)
print(res.content)
with open("baidu.png", mode="wb", ) as file:
    file.write(res.content)



你可能感兴趣的:(学习日记,python,测试工程师)