python+requests接口自动化框架的实现

news2024/10/6 0:29:18

为什么要做接口自动化框架

1、业务与配置的分离

2、数据与程序的分离;数据的变更不影响程序

3、有日志功能,实现无人值守

4、自动发送测试报告

5、不懂编程的测试人员也可以进行测试

正常接口测试的流程是什么?

确定接口测试使用的工具----->配置需要的接口参数----->进行测试----->检查测试结果----->生成测试报告

测试的工具:python+requests

接口测试用例:excel

一、接口框架如下:

1、action包:用来存放关键字函数

2、config包:用来存放配置文件

3、TestData:用来存放测试数据,excel表

4、Log包:用来存放日志文件

5、utils包:用来存放公共的类

6、运行主程序interface_auto_test.py

7、Readme.txt:告诉团队组员使用改框架需要注意的地方

二、接口的数据规范设计---Case设计

一个sheet对应数据库里面一张表

APIsheet存放
编号;从1开始
接口的名称(APIName);
请求的url(RequestUrl);
请求的方法(RequestMethod);
传参的方式(paramsType):post/get请求方法不一样
用例说明(APITestCase)
是否执行(Active)部分接口已测通,下次不用测试,直接把这里设置成N,跳过此接口

post与get的区别

查看post详情

post请求参数一般是json串,参数放在from表单里面;参数一般不可见,相对来说安全性高些

查看get详情

get请求参数一般直接放在url里面

2.1注册接口用例

RequestData:请求的数据
(开发制定的传参方式)
RelyData:数据依赖
ResponseCode:响应code
ResponseData:响应数据
DataStore:存储的依赖数据;如果存在数据库里面,在表里增加一个字段用来存依赖的数据
(存储的方式是编写接口自动化的人员来设定的存储方式)
CheckPoint:检查点
Active:是否执行
Status:执行用例的状态,方便查看用例是否执行成功
ErrorInfo:case运行失败,失败的错误信息;eg:是也本身的原因还是case设置失败,还是其他原因

2.2登录接口用例

RequestData:请求的数据
(开发制定的传参方式)
RelyData:数据依赖
(存储的方式是编写接口自动化的人员来设定的存储方式)
ResponseCode:响应code
ResponseData:响应数据
DataStore:存储的依赖数据;如果存在数据库里面,在表里增加一个字段用来存依赖的数据
(存储的方式是编写接口自动化的人员来设定的存储方式)
CheckPoint:检查点
Active:是否执行
Status:执行用例的状态,方便查看用例是否执行成功
ErrorInfo:case运行失败,失败的错误信息;eg:是也本身的原因还是case设置失败,还是其他原因

重点说明下RelyData:数据依赖
采取的是字典:key:value来存储数据格式;
{"request":{"username":"register->1","password":"register->1"},"response":{"code":"register->1"}}

格式化之后:

1

2

3

4

5

6

7

8

9

{

  "request":{

    "username":"register->1",

    "password":"register->1"

  },

  "response":{

    "code":"register->1"

  }

}

三、创建utils包:用来存放公共的类

3.1 ParseExcel.py 操作封装excel的类(ParseExcel.py)

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

#encoding=utf-8

import openpyxl

from openpyxl.styles import Border, Side, Font

import time

class ParseExcel(object):

  def __init__(self):

    self.workbook = None

    self.excelFile = None

    self.font = Font(color = None) # 设置字体的颜色

    # 颜色对应的RGB值

    self.RGBDict = {'red': 'FFFF3030', 'green': 'FF008B00'}

  def loadWorkBook(self, excelPathAndName):

    # 将excel文件加载到内存,并获取其workbook对象

    try:

      self.workbook = openpyxl.load_workbook(excelPathAndName)

    except Exception as err:

      raise err

    self.excelFile = excelPathAndName

    return self.workbook

  def getSheetByName(self, sheetName):

    # 根据sheet名获取该sheet对象

    try:

      # sheet = self.workbook.get_sheet_by_name(sheetName)

      sheet = self.workbook[sheetName]

      return sheet

    except Exception as err:

      raise err

  def getSheetByIndex(self, sheetIndex):

    # 根据sheet的索引号获取该sheet对象

    try:

      # sheetname = self.workbook.get_sheet_names()[sheetIndex]

      sheetname = self.workbook.sheetnames[sheetIndex]

    except Exception as err:

      raise err

    # sheet = self.workbook.get_sheet_by_name(sheetname)

    sheet = self.workbook[sheetname]

    return sheet

  def getRowsNumber(self, sheet):

    # 获取sheet中有数据区域的结束行号

    return sheet.max_row

  def getColsNumber(self, sheet):

    # 获取sheet中有数据区域的结束列号

    return sheet.max_column

  def getStartRowNumber(self, sheet):

    # 获取sheet中有数据区域的开始的行号

    return sheet.min_row

  def getStartColNumber(self, sheet):

    # 获取sheet中有数据区域的开始的列号

    return sheet.min_column

  def getRow(self, sheet, rowNo):

    # 获取sheet中某一行,返回的是这一行所有的数据内容组成的tuple,

    # 下标从1开始,sheet.rows[1]表示第一行

    try:

      rows = []

      for row in sheet.iter_rows():

        rows.append(row)

      return rows[rowNo - 1]

    except Exception as err:

      raise err

  def getColumn(self, sheet, colNo):

    # 获取sheet中某一列,返回的是这一列所有的数据内容组成tuple,

    # 下标从1开始,sheet.columns[1]表示第一列

    try:

      cols = []

      for col in sheet.iter_cols():

        cols.append(col)

      return cols[colNo - 1]

    except Exception as err:

      raise err

  def getCellOfValue(self, sheet, coordinate = None,

            rowNo = None, colsNo = None):

    # 根据单元格所在的位置索引获取该单元格中的值,下标从1开始,

    # sheet.cell(row = 1, column = 1).value,

    # 表示excel中第一行第一列的值

    if coordinate != None:

      try:

        return sheet[coordinate]

      except Exception as err:

        raise err

    elif coordinate is None and rowNo is not None and \

            colsNo is not None:

      try:

        return sheet.cell(row = rowNo, column = colsNo).value

      except Exception as err:

        raise err

    else:

      raise Exception("Insufficient Coordinates of cell !")

  def getCellOfObject(self, sheet, coordinate = None,

            rowNo = None, colsNo = None):

    # 获取某个单元格的对象,可以根据单元格所在位置的数字索引,

    # 也可以直接根据excel中单元格的编码及坐标

    # 如getCellObject(sheet, coordinate = 'A1') or

    # getCellObject(sheet, rowNo = 1, colsNo = 2)

    if coordinate != None:

      try:

        # return sheet.cell(coordinate = coordinate)

        return sheet[coordinate]

      except Exception as err:

        raise err

    elif coordinate == None and rowNo is not None and \

            colsNo is not None:

      try:

        return sheet.cell(row = rowNo,column = colsNo)

      except Exception as err:

        raise err

    else:

      raise Exception("Insufficient Coordinates of cell !")

  def writeCell(self, sheet, content, coordinate = None,

    rowNo = None, colsNo = None, style = None):

    #根据单元格在excel中的编码坐标或者数字索引坐标向单元格中写入数据,

    # 下标从1开始,参style表示字体的颜色的名字,比如red,green

    if coordinate is not None:

      try:

        # sheet.cell(coordinate = coordinate).value = content

        sheet[coordinate] = content

        if style is not None:

          sheet[coordinate].\

            font = Font(color = self.RGBDict[style])

        self.workbook.save(self.excelFile)

      except Exception as e:

        raise e

    elif coordinate == None and rowNo is not None and \

            colsNo is not None:

      try:

        sheet.cell(row = rowNo,column = colsNo).value = content

        if style:

          sheet.cell(row = rowNo,column = colsNo).\

            font = Font(color = self.RGBDict[style])

        self.workbook.save(self.excelFile)

      except Exception as e:

        raise e

    else:

      raise Exception("Insufficient Coordinates of cell !")

  def writeCellCurrentTime(self, sheet, coordinate = None,

        rowNo = None, colsNo = None):

    # 写入当前的时间,下标从1开始

    now = int(time.time()) #显示为时间戳

    timeArray = time.localtime(now)

    currentTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)

    if coordinate is not None:

      try:

        sheet.cell(coordinate = coordinate).value = currentTime

        self.workbook.save(self.excelFile)

      except Exception as e:

        raise e

    elif coordinate == None and rowNo is not None \

        and colsNo is not None:

      try:

        sheet.cell(row = rowNo, column = colsNo

            ).value = currentTime

        self.workbook.save(self.excelFile)

      except Exception as e:

        raise e

    else:

      raise Exception("Insufficient Coordinates of cell !")

if __name__ == '__main__':

  # 测试代码

  pe = ParseExcel()

  pe.loadWorkBook(r'D:\ProgramSourceCode\Python Source Code\WorkSpace\InterfaceFrame2018\inter_test_data.xlsx')

  sheetObj = pe.getSheetByName(u"API")

  print("通过名称获取sheet对象的名字:", sheetObj.title)

  # print help(sheetObj.rows)

  print("通过index序号获取sheet对象的名字:", pe.getSheetByIndex(0).title)

  sheet = pe.getSheetByIndex(0)

  print(type(sheet))

  print(pe.getRowsNumber(sheet)) #获取最大行号

  print(pe.getColsNumber(sheet)) #获取最大列号

  rows = pe.getRow(sheet, 1) #获取第一行

  for i in rows:

    print(i.value)

  # # 获取第一行第一列单元格内容

  # print pe.getCellOfValue(sheet, rowNo = 1, colsNo = 1)

  # pe.writeCell(sheet, u'我爱祖国', rowNo = 10, colsNo = 10)

  # pe.writeCellCurrentTime(sheet, rowNo = 10, colsNo = 11)

3.2 封装get/post请求(HttpClient.py)

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

import requests

import json

class HttpClient(object):

  def __init__(self):

    pass

  def request(self, requestMethod, requestUrl, paramsType,

        requestData, headers =None, **kwargs):

    if requestMethod == "post":

      print("---", requestData, type(requestData))

      if paramsType == "form":

        response = self.__post(url = requestUrl, data = json.dumps(eval(requestData)),

                 headers = headers, **kwargs)

        return response

      elif paramsType == "json":

        response = self.__post(url = requestUrl, json = json.dumps(eval(requestData)),

                 headers = headers, **kwargs)

        return response

    elif requestMethod == "get":

      request_url = requestUrl

      if paramsType == "url":

        request_url = "%s%s" %(requestUrl, requestData)

      response = self.__get(url = request_url, params = requestData, **kwargs)

      return response

  def __post(self, url, data = None, json = None, headers=None,**kwargs):

    print("----")

    response = requests.post(url=url, data = data, json=json, headers=headers)

    return response

  def __get(self, url, params = None, **kwargs):

    response = requests.get(url, params = params, **kwargs)

    return response

if __name__ == "__main__":

  hc = HttpClient()

  res = hc.request("get", "http://39.106.41.11:8080/getBlogContent/", "url",'2')

  print(res.json())

3.3 封装MD5(md5_encrypt)

1

2

3

4

5

6

7

8

9

10

import hashlib

def md5_encrypt(text):

  m5 = hashlib.md5()

  m5.update(text.encode("utf-8"))

  value = m5.hexdigest()

  return value

if __name__ == "__main__":

  print(md5_encrypt("sfwe"))

3.4 封装Log

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import logging

import logging.config

from config.public_data import baseDir

# 读取日志配置文件

logging.config.fileConfig(baseDir + "\config\Logger.conf")

# 选择一个日志格式

logger = logging.getLogger("example02")#或者example01

def debug(message):

  # 定义dubug级别日志打印方法

  logger.debug(message)

def info(message):

  # 定义info级别日志打印方法

  logger.info(message)

def warning(message):

  # 定义warning级别日志打印方法

  logger.warning(message)

3.5 封装发送Email类

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

44

45

46

47

48

49

50

51

52

53

54

55

import smtplib

from email.mime.text import MIMEText

from email.mime.multipart import MIMEMultipart

from email.header import Header

from ProjVar.var import *

import os

import smtplib

from email import encoders

from email.mime.base import MIMEBase

from email.mime.text import MIMEText

from email.mime.multipart import MIMEMultipart

from email.header import Header

from email.utils import formataddr

def send_mail():

  mail_host="smtp.126.com" #设置服务器

  mail_user="testman1980"  #用户名

  mail_pass="wulaoshi1980"  #口令

  sender = 'testman1980@126.com'

  receivers = ['2055739@qq.com',"testman1980@126.com"] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱

  # 创建一个带附件的实例

  message = MIMEMultipart()

  message['From'] = formataddr(["光荣之路吴老师", "testman1980@126.com"])

  message['To'] = ','.join(receivers)

  subject = '自动化测试执行报告'

  message['Subject'] = Header(subject, 'utf-8')

  message["Accept-Language"]="zh-CN"

  message["Accept-Charset"]="ISO-8859-1,utf-8,gbk"

  # 邮件正文内容

  message.attach(MIMEText('最新执行的自动化测试报告,请参阅附件内容!', 'plain', 'utf-8'))

  # 构造附件1,传送测试结果的excel文件

  att = MIMEBase('application', 'octet-stream')

  att.set_payload(open(ProjDirPath+"\\testdata\\testdata.xlsx", 'rb').read())

  att.add_header('Content-Disposition', 'attachment', filename=('gbk', '', "自动化测试报告.xlsx"))

  encoders.encode_base64(att)

  message.attach(att)

  """

  # 构造附件2,传送当前目录下的 runoob.txt 文件

  att2 = MIMEText(open('e:\\a.py','rb').read(), 'base64', 'utf-8')

  att2["Content-Type"] = 'application/octet-stream'

  att2["Content-Disposition"] = 'attachment; filename="a.py"'

  message.attach(att2)

  """

  try:

    smtpObj = smtplib.SMTP(mail_host)

    smtpObj.login(mail_user, mail_pass)

    smtpObj.sendmail(sender, receivers, message.as_string())

    print("邮件发送成功")

  except smtplib.SMTPException as e:

    print("Error: 无法发送邮件", e)

if __name__ == "__main__":

  send_mail()

四、 创建config包 用来存放公共的参数、配置文件、长时间不变的变量值

创建public_data.py

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

import os

# 整个项目的根目录绝对路劲

baseDir = os.path.dirname(os.path.dirname(__file__))

# 获取测试数据文件的绝对路径

file_path = baseDir + "/TestData/inter_test_data.xlsx"

API_apiName = 2

API_requestUrl = 3

API_requestMothod = 4

API_paramsType = 5

API_apiTestCaseFileName = 6

API_active = 7

CASE_requestData = 1

CASE_relyData = 2

CASE_responseCode = 3

CASE_responseData = 4

CASE_dataStore = 5

CASE_checkPoint = 6

CASE_active = 7

CASE_status = 8

CASE_errorInfo = 9

# 存储请求参数里面依赖的数据

REQUEST_DATA = {}

# 存储响应对象中的依赖数据

RESPONSE_DATA = {}

if __name__=="__main__":

  print(file_path)

  print(baseDir)

五、创建TestData目录,用来存放测试文件

inter_test_data.xlsx

六、创建action包,用来存放关键字函数

6.1 解决数据依赖 (GetRely.py)

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

44

45

46

47

48

49

50

51

52

from config.public_data import REQUEST_DATA, RESPONSE_DATA

from utils.md5_encrypt import md5_encrypt

REQUEST_DATA = {"用户注册":{"1":{"username":"zhangsan", "password":"dfsdf23"},

            "headers":{"cookie":"asdfwerw"}}}

RESPONSE_DATA = {"用户注册":{"1":{"code":"00"}, "headers":{"age":2342}}}

class GetRely(object):

  def __init__(self):

    pass

  @classmethod

  def get(self, dataSource, relyData, headSource = {}):

    print(type(dataSource))

    print(dataSource)

    data = dataSource.copy()

    for key, value in relyData.items():

      if key == "request":

        #说明应该去REQUEST_DATA中获取

        for k, v in value.items():

          interfaceName, case_idx = v.split("->")

          val = REQUEST_DATA[interfaceName][case_idx][k]

          if k == "password":

            data[k] = md5_encrypt(val)

          else:

            data[k] = val

      elif key == "response":

        # 应该去RESPONSE_DATA中获取

        for k, v in value.items():

          interfaceName, case_idx = v.split("->")

          data[k] = RESPONSE_DATA[interfaceName][case_idx][k]

      elif key == "headers":

        if headSource:

          for key, value in value.items():

            if key == "request":

              for k, v in value.items():

                for i in v:

                  headSource[i] = REQUEST_DATA[k]["headers"][i]

            elif key == "response":

              for i, val in value.items():

                for j in val:

                  headSource[j] = RESPONSE_DATA[i]["headers"][j]

    return "%s" %data

if __name__ == "__main__":

  s = {"username": "", "password": "","code":""}

  h = {"cookie":"123", "age":332}

  rely = {"request": {"username": "用户注册->1", "password": "用户注册->1"},

      "response":{"code":"用户注册->1"},

      "headers":{"request":{"用户注册":["cookie"]},"response":{"用户注册":["age"]}}

      }

  print(GetRely.get(s, rely, h))

6.2 解决数据存储(RelyDataStore.py)

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

from config.public_data import RESPONSE_DATA, REQUEST_DATA

class RelyDataStore(object):

  def __init__(self):

    pass

  @classmethod

  def do(cls, storePoint, apiName, caseId, request_source = {}, response_source = {}, req_headers={}, res_headers = {}):

    for key, value in storePoint.items():

      if key == "request":

        # 说明需要存储的依赖数据来自请求参数,应该将数据存储到REQUEST_DATA

        for i in value:

          if i in request_source:

            val = request_source[i]

            if apiName not in REQUEST_DATA:

              # 说明存储数据的结构还未生成,需要指明数据存储结构

              REQUEST_DATA[apiName]={str(caseId): {i: val}}

            else:

              #说明存储数据结构中最外层结构已存在

              if str(caseId) in REQUEST_DATA[apiName]:

                REQUEST_DATA[apiName][str(caseId)][i] = val

              else:

                # 说明内层结构不完整,需要指明完整的结构

                REQUEST_DATA[apiName][str(caseId)] = {i: val}

          else:

            print("请求参数中不存在字段" + i)

      elif key == "response":

        #说明需要存储的依赖数据来自接口的响应body,应该将数据存储到RESPONSE_DATA

        for j in value:

          if j in response_source:

            val = response_source[j]

            if apiName not in RESPONSE_DATA:

              # 说明存储数据的结构还未生成,需要指明数据存储结构

              RESPONSE_DATA[apiName]={str(caseId): {j: val}}

            else:

              #说明存储数据结构中最外层结构已存在

              if str(caseId) in RESPONSE_DATA[apiName]:

                RESPONSE_DATA[apiName][str(caseId)][j] = val

              else:

                # 说明内层结构不完整,需要指明完整的结构

                RESPONSE_DATA[apiName][str(caseId)] = {j: val}

          else:

            print("接口的响应body中不存在字段" + j)

      elif key == "headers":

        for k, v in value.items():

          if k == "request":

            # 说明需要往REQUEST_DATA变量中写入存储数据

            for item in v:

              if item in req_headers:

                header = req_headers[item]

                if "headers" in REQUEST_DATA[apiName]:

                  REQUEST_DATA[apiName]["headers"][item] = header

                else:

                  REQUEST_DATA[apiName]["headers"] = {item: header}

          elif k == "response":

            # 说明需要往RESPONSE_DATA变量中写入存储数据

            for it in v:

              if it in res_headers:

                header = res_headers[it]

                if "headers" in RESPONSE_DATA[apiName]:

                  RESPONSE_DATA[apiName]["headers"][it] = header

                else:

                  RESPONSE_DATA[apiName]["headers"] = {item: header}

    print(REQUEST_DATA)

    print(RESPONSE_DATA)

if __name__ == "__main__":

  r = {"username": "srwcx01", "password": "wcx123wac1", "email": "wcx@qq.com"}

  req_h = {"cookie":"csdfw23"}

  res_h = {"age":597232}

  s = {"request": ["username", "password"], "response": ["userid"],"headers":{"request":["cookie"],

    "response":["age"]}}

  res = {"userid": 12, "code": "00"}

  RelyDataStore.do(s, "register", 1, r, res, req_headers=req_h, res_headers=res_h)

  print(REQUEST_DATA)

  print(RESPONSE_DATA)

6.3 校验数据结果(CheckResult.py)

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

import re

class CheckResult(object):

  def __init__(self):

    pass

  @classmethod

  def check(self, responseObj, checkPoint):

    responseBody = responseObj.json()

    # responseBody = {"code": "", "userid": 12, "id": "12"}

    errorKey = {}

    for key, value in checkPoint.items():

      if key in responseBody:

        if isinstance(value, (str, int)):

          # 等值校验

          if responseBody[key] != value:

            errorKey[key] = responseBody[key]

        elif isinstance(value, dict):

          sourceData = responseBody[key]

          if "value" in value:

            # 模糊匹配校验

            regStr = value["value"]

            rg = re.match(regStr, "%s" %sourceData)

            if not rg:

              errorKey[key] = sourceData

          elif "type" in value:

            # 数据类型校验

            typeS = value["type"]

            if typeS == "N":

              # 说明是整形校验

              if not isinstance(sourceData, int):

                errorKey[key] = sourceData

      else:

        errorKey[key] = "[%s] not exist" %key

    return errorKey

if __name__ == "__main__":

  r = {"code": "00", "userid": 12, "id": 12}

  c = {"code": "00", "userid": {"type": "N"}, "id": {"value": "\d+"}}

  print(CheckResult.check(r, c))

6.4 往excel里面写结果

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

from config.public_data import *

def write_result(wbObj, sheetObj, responseData, errorKey, rowNum):

  try:

    # 写响应body

    wbObj.writeCell(sheetObj, content="%s" %responseData,

            rowNo = rowNum, colsNo=CASE_responseData)

    # 写校验结果状态及错误信息

    if errorKey:

      wbObj.writeCell(sheetObj, content="%s" %errorKey,

            rowNo=rowNum, colsNo=CASE_errorInfo)

      wbObj.writeCell(sheetObj, content="faild",

              rowNo=rowNum, colsNo=CASE_status, style="red")

    else:

      wbObj.writeCell(sheetObj, content="pass",

              rowNo=rowNum, colsNo=CASE_status, style="green")

  except Exception as err:

    raise err

七、创建Log目录用来存放日志

八、主函数

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

#encoding=utf-8

import requests

import json

from action.get_rely import GetRely

from config.public_data import *

from utils.ParseExcel import ParseExcel

from utils.HttpClient import HttpClient

from action.data_store import RelyDataStore

from action.check_result import CheckResult

from action.write_result import write_result

from utils.Log import *

def main():

  parseE = ParseExcel()

  parseE.loadWorkBook(file_path)

  sheetObj = parseE.getSheetByName("API")

  activeList = parseE.getColumn(sheetObj, API_active)

  for idx, cell in enumerate(activeList[1:], 2):

    if cell.value == "y":

      #需要被执行

      RowObj = parseE.getRow(sheetObj, idx)

      apiName = RowObj[API_apiName -1].value

      requestUrl = RowObj[API_requestUrl - 1].value

      requestMethod = RowObj[API_requestMothod - 1].value

      paramsType = RowObj[API_paramsType - 1].value

      apiTestCaseFileName = RowObj[API_apiTestCaseFileName - 1].value

      # 下一步读取用例sheet表,准备执行测试用例

      caseSheetObj = parseE.getSheetByName(apiTestCaseFileName)

      caseActiveObj = parseE.getColumn(caseSheetObj, CASE_active)

      for c_idx, col in enumerate(caseActiveObj[1:], 2):

        if col.value == "y":

          #需要执行的用例

          caseRowObj = parseE.getRow(caseSheetObj, c_idx)

          requestData = caseRowObj[CASE_requestData - 1].value

          relyData = caseRowObj[CASE_relyData - 1].value

          responseCode = caseRowObj[CASE_responseCode - 1].value

          responseData = caseRowObj[CASE_responseData - 1].value

          dataStore = caseRowObj[CASE_dataStore -1].value

          checkPoint = caseRowObj[CASE_checkPoint - 1].value

          #发送接口请求之前需要做一下数据依赖的处理

          if relyData:

            logging.info("处理第%s个接口的第%s条用例的数据依赖!")

            requestData = GetRely.get(eval(requestData), eval(relyData))

          httpC = HttpClient()

          response = httpC.request(requestMethod=requestMethod,

                       requestData=requestData,

                       requestUrl=requestUrl,

                       paramsType=paramsType

                       )

          # 获取到响应结果后,接下来进行数据依赖存储逻辑实现

          if response.status_code == 200:

            responseData = response.json()

            # 进行依赖数据存储

            if dataStore:

              RelyDataStore.do(eval(dataStore), apiName, c_idx - 1, eval(requestData), responseData)

            # 接下来就是校验结果

            else:

              logging.info("接口【%s】的第【%s】条用例,不需要进行依赖数据存储!" %(apiName, c_idx))

            if checkPoint:

              errorKey = CheckResult.check(response, eval(checkPoint))

              write_result(parseE, caseSheetObj, responseData, errorKey, c_idx)

          else:

            logging.info("接口【%s】的第【%s】条用例,执行失败,接口协议code非200!" %(apiName, c_idx))

        else:

          logging.info("第%s个接口的第%s条用例,被忽略执行!" %(idx -1, c_idx-1))

    else:

      logging.info("第%s行的接口被忽略执行!" %(idx -1))

if __name__=="__main__":

  main()

​现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:485187702【暗号:csdn11】

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你!【100%无套路免费领取】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1510531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内部应用解耦神器-Spring事件

大家好,我是程序员牛牛,《AI超级个体: ChatGPT与AIGC实战指南》的参与人,10年Java编程程序员。 1. 概述 在做业务开发过程中,有些复杂点的逻辑,可能代码逻辑会很冗长,举一个很简单的例子,如&am…

windows解决nodejs版本冲突:安装版本管理器nvm,可根据不同项目一键切换适配版本

windows解决nodejs版本冲突:安装版本管理器nvm,可根据不同项目一键切换适配版本 参考来源:在本机 Windows 上设置 NodeJS | Microsoft Learn 建议安装版本管理器 nvm-windows,再用它来安装 Node.js 和 npm,这样可以根据…

C++学习笔记:红黑树

红黑树 什么是红黑树红黑树的规则红黑树节点的定义红黑树的插入空树插入非空插入条件判断新插入的节点 cur 不为 root 且 parent->_col 为红就需要调整父节点为左 grandf->left parent当uncle节点为红色时,只需要进行颜色调整,即可当uncle为空 或 者存在但是为黑parent …

Midjourney能让角色保持一致了

Midjourney发布新功能,网友直呼“不可思议”! 现在你可以让生成的图像几乎保持角色一致,belike: 所有超级英雄长一个模样盯着你。 甚至动漫风、写实风等跨风格生成也同样适用: 保持同一风格,感jio配上文字…

【FPGA】DDR3学习笔记(一)丨SDRAM原理详解

本篇文章包含的内容 一、DDR3简介1.1 DDR3 SDRAM概述1.2 SDRAM的基础结构 二、 SDRAM操作时序2.1 SDRAM操作指令2.2 模式寄存器(LOAD MODE REGISTER)2.3 SDRAM操作时序示例2.3.1 SDRAM初始化时序2.3.2 突发读时序2.3.3 随机读时序2.3.4 突发写时序2.3.5 …

Java基础-接口

文章目录 1.快速入门代码:结果: 2.接口基本介绍1.语法注意:在jdk1.8以后接口才可以有静态方法,默认方法 2.代码实例 3.接口的应用场景1.场景介绍2.代码实例4.接口使用细节 5.接口课堂练习题目:答案:注意&am…

深入理解,java标识符?类型转换?

1、标识符 下面这张图是中国的一些姓氏 中国人起名字的规则都是以姓开头,名结尾。通过这个规则可以起:刘爱国、张三等,都是以汉字起的。但是不会起李ad、王123等名字,因为不符合规则。 所以,java在给变量、方法、类等…

【C++进阶】C++继承概念详解

C继承详解 一,继承的概念和定义1.1 继承的概念1.2 继承的定义1.3 继承关系和访问限定符 二,基类和派生类的对象赋值转移三,继承的作用域四,派生类的默认成员函数五,继承和友元&静态成员和继承六,菱形继…

Ansys Lumerical | 激光雷达天线仿真

附件下载 联系工作人员获取附件 在本文中,我们将了解如何根据激光雷达应用需求设计和优化相控阵光栅天线。 概述 激光雷达(LIDAR)是“light detection and ranging”的简称,近年来由于在机器人、自动驾驶汽车、高精度测绘等领域…

【AcWing】蓝桥杯集训每日一题Day2|前缀和|562.壁画(C++)

562. 壁画 562. 壁画 - AcWing题库难度:中等时/空限制:1s / 64MB总通过数:4154总尝试数:10197来源:Google Kickstart2018 Round H Problem B算法标签 思维题枚举前缀和 题目内容 Thanh 想在一面被均分为 N 段的墙上画…

[java——基础] 双亲委派机制

目录 核心思想: 双亲委派机制的好处: 三种类加载器 解析源代码 双亲委派思想面试总结: 核心思想: 向上搜索,向下加载。 双亲委派机制的好处: 防止Java核心类被篡改,防止类的重复加载。 三…

哈希表|15.三数之和

力扣题目链接 int cmp(const void *a,const void *b) {return *(int*)a - *(int*)b;} int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {*returnSize 0;if(numsSize < 3)return NULL;qsort(nums, numsSize, sizeof(int),cmp);int **…

C++ Qt开发:QNetworkAccessManager网络接口组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QNetworkAccessManager组件实现Web网…

Java日志框架Log4j 2详解

目录 一、什么是日志&#xff1f; 二、日志的主要用途 三、常用日志框架 1、Apache Log4j 2、Commons Logging 3、SLF4J 4、Logback 5、JUL(Java Util Logging) 6、Log4j 2 四、log4j 2 的优点 五、Log4j 2下载和配置 1、访问Log4j – 下载 Apache Log4j™ 2官网&a…

RHEL9 DNF/YUM仓库管理软件包

DNF/YUM仓库管理软件包 一个基于RPM包的软件包管理器能够从指定的服务器自动下载RPM包并且安装&#xff0c;自动处理依赖性关系&#xff0c;并且一次性安装所有依赖的软件包C/S模式 Server服务端提供RPM软件包与数据库文件repodataClient客户端使用dnf仓库 常用组合 组合参…

你还可以通过“nrm”工具,来自由管理“npm”的镜像

你还可以通过“nrm”工具&#xff0c;来自由管理“npm”的镜像 nrm&#xff08;npm registry manager&#xff09;是npm的镜像管理工具&#xff0c;有时候国外的资源太慢&#xff0c;使用这个就可以快速地在npm源间切换。 1.安装nrm 在命令行执行命令&#xff0c;npm install…

Java 容器启动执行指定任务

1、实现CommandLineRunner接口 实现CommandLineRunner接口&#xff0c;注意做初始化任务的类需要放在扫描路径下&#xff0c;使用Component注入到spring容器中。 import com.zw.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; impo…

网络安全AI智能体公司「云起无垠」获数千万元天使+轮融资,致力于大模型与网络安全深度融合的技术研究

「云起无垠」致力于打造最懂安全的AI智能体&#xff0c;通过持续运营的工具、知识以及记忆引擎&#xff0c;不断提升智能体对用户安全场景的理解&#xff0c;以达到易于使用、自我学习、自主行动的特性&#xff0c;助力企业自动化执行各类安全任务&#xff0c;让软件更安全&…

在WSL2中安装多个Ubuntu教程

文章目录 前言一、前期准备1、WSL安装2、Docker安装 二、安装第二个Ubuntu系统1.切换为WSL22.获取Ubuntu16.04的tar文件从容器中导出tar 3. 将tar文件导入WSL4. 设置默认用户 总结 前言 适用于 Linux 的 Windows 子系统 (WSL) 是 Windows 的一项功能&#xff0c;可用于在 Wind…

H12-811_19

19.(多选题)如下图所示的网络&#xff0c;下列哪些命令可以使RouterA可以转发目的IP地址为10.0.3.3的效据包? A.ip route-static 10.0.3.3 255.255.255.255 10.0.12.2 B.ip route-static 10.0.2.2 255.255.255.255 10.0.12.2 ip route-static 10.0.3.3 255.255.255.255 10.0…