ToB企服应用市场:ToB评测及商务社交产业平台

标题: Python+requests接口主动化测试框架实例教程 [打印本页]

作者: 吴旭华    时间: 2025-2-14 04:47
标题: Python+requests接口主动化测试框架实例教程
前段时间由于公司测试方向的转型,由原来的web页面功能测试转变成接口测试,之前大多都是手工举行,利用postman和jmeter举行的接口测试,后来,组内有人讲原先web主动化的测试框架移驾成接口的主动化框架,使用的是java语言,但对于一个学java,却在学python的我来说,以为python比起java更简单些。
所以,我决定自己写python的接口主动化测试框架,由于本人也是刚学习python,这套主动化框架目前已经基本完成了,于是举行一些总结,便于以后回顾温习,有许多不完善的地方,也碰到了许多的标题,希望大神们多多指教。
下面我就举行本日的重要内容吧。
1、起首,我们先来理一下思路。
正常的接口测试流程是什么?
脑海里的反应是不是这样的:
确定测试接口的工具 —> 配置需要的接口参数 —> 举行测试 —> 查抄测试结果(有的需要数据库辅助) —> 生成测试报告(html报告)
那么,我们就根据这样的过程来一步步搭建我们的框架。在这个过程中,我们需要做到业务和数据的分离,这样才能机动,达到我们写框架的目的。只要好好做,肯定可以成功。这也是我当初对自己说的。
接下来,我们来举行结构的划分。
我的结构是这样的,各人可以参考下

既然整体结构有了划分,接下来就该一步步的填充整个框架了,起首,我们先来看看config.ini和readConfig.py两个文件,从他们入手,个人以为比较容易走下去哒。
我们来看下文件的内容是什么样子的:
  1. [DATABASE]
  2. host = 50.23.190.57
  3. username = xxxxxx
  4. password = ******
  5. port = 3306
  6. database = databasename
  7. [HTTP]
  8. # 接口的url
  9. baseurl = http://xx.xxxx.xx
  10. port = 8080
  11. timeout = 1.0
  12. [EMAIL]
  13. mail_host = smtp.163.com
  14. mail_user = xxx@163.com
  15. mail_pass = *********
  16. mail_port = 25
  17. sender = xxx@163.com
  18. receiver = xxxx@qq.com/xxxx@qq.com
  19. subject = python
  20. content = "All interface test has been complited\nplease read the report file about the detile of result in the attachment."
  21. testuser = Someone
  22. on_off = 1
复制代码
相信各人都知道这样的配置文件,没错,所有一成不变的东西,我们都可以放到这里来。哈哈,怎么样,不错吧。
现在,我们已经做好了固定的“堆栈”。来生存我们平时不动的东西,那么,我们要怎么把它拿出来为我所用呢?
这时候,readConfig.py文件出世了,它成功的帮我们解决了这个标题,下面就让我们来一睹它的庐山真面目吧。
  1. import os
  2. import codecs
  3. import configparser
  4. proDir = os.path.split(os.path.realpath(__file__))[0]
  5. configPath = os.path.join(proDir, "config.ini")
  6. class ReadConfig:
  7. def __init__(self):
  8.         fd = open(configPath)
  9.         data = fd.read()
  10. #  remove BOM
  11. if data[:3] == codecs.BOM_UTF8:
  12.             data = data[3:]
  13.             file = codecs.open(configPath, "w")
  14.             file.write(data)
  15.             file.close()
  16.         fd.close()
  17. self.cf = configparser.ConfigParser()
  18.         self.cf.read(configPath)
  19. def get_email(self, name):
  20.         value = self.cf.get("EMAIL", name)
  21.         return value
  22. def get_http(self, name):
  23.         value = self.cf.get("HTTP", name)
  24.         return value
  25. def get_db(self, name):
  26.         value = self.cf.get("DATABASE", name)
  27. return value
复制代码
怎么样,是不是看着很简单啊,我们定义的方法,根据名称取对应的值,是不是so easy?!当然了,这里我们只用到了get方法,还有其他的例如set方法,有爱好的同砚可以自己去探索下。
话不多说,我们先来看下common到底有哪些东西。

既然配置文件和读取配置文件我们都已经完成了,也看到了common里的内容,接下来就可以写common里的共通方法了,从哪个动手呢?本日,我们就来翻“Log.py”的牌吧,由于它是比较独立的,我们单独跟他打交道,也为了以后它能为我们服务打下精良基础。
这里呢,我想跟各人多说两句,对于这个log文件呢,我给它单独启用了一个线程,这样在整个运行过程中,我们在写log的时候也会比较方便,看名字各人也知道了,这里就是我们对输出的日志的所有操纵了,重要是对输特别式的规定,输出等级的定义以及其他一些输出的定义等等。
总之,你想对log做的任何事变,都可以放到这里来。我们来看下代码,没有比这个更直接有效的了。
  1. import logging
  2. from datetime import datetime
  3. import threading
复制代码
起首,我们要像上面那样,引入需要的模块,才能举行接下来的操纵。
  1. class Log:
  2. def __init__(self):
  3.         global logPath, resultPath, proDir
  4.         proDir = readConfig.proDir
  5.         resultPath = os.path.join(proDir, "result")
  6. # create result file if it doesn't exist
  7. if not os.path.exists(resultPath):
  8.             os.mkdir(resultPath)
  9. # defined test result file name by localtime
  10.         logPath = os.path.join(resultPath, str(datetime.now().strftime("%Y%m%d%H%M%S")))
  11. # create test result file if it doesn't exist
  12. if not os.path.exists(logPath):
  13.             os.mkdir(logPath)
  14. # defined logger
  15. self.logger = logging.getLogger()
  16. # defined log level
  17.         self.logger.setLevel(logging.INFO)
  18. # defined handler
  19.         handler = logging.FileHandler(os.path.join(logPath, "output.log"))
  20. # defined formatter
  21.         formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  22. # defined formatter
  23.         handler.setFormatter(formatter)
  24. # add handler
  25. self.logger.addHandler(handler)
复制代码
现在,我们创建了上面的Log类,在__init__初始化方法中,我们举行了log的相关初始化操纵。
具体的操纵内容,注释已经写得很清楚了(英文有点儿差,各人看得懂就行,嘿嘿……),这样,log的基本格式已经定义完成了,至于其他的方法,就靠各人自己发挥了,究竟每个人的需求也差别,我们就只写广泛的共用方法啦。接下来,就是把它放进一个线程内了,请看下面的代码:​​​​​​​
  1. class MyLog:
  2.     log = None
  3.     mutex = threading.Lock()
  4. def __init__(self):
  5.         pass
  6.     @staticmethod
  7. def get_log():
  8. if MyLog.log is None:
  9.             MyLog.mutex.acquire()
  10.             MyLog.log = Log()
  11.             MyLog.mutex.release()
  12. return MyLog.log
复制代码
看起来是不是没有想象中的那样复杂啊,哈哈哈,就是这样简单,python比java简单了许多,这也是我为什么选择它的缘故原由,虽然小编我也是刚刚学习,还有很多不懂的地方。
好了,至此log的内容也结束了,是不是感觉自己棒棒哒~其实,无论什么时候,都不要感到畏惧,要相信“世上无难事只怕故意人”。
下面,我们继续搭建,这次要做的,是configHttp.py的内容。没错,我们开始配置接口文件啦!(终于写到接口了,是不是很开心啊~)
下面是接口文件中重要部门的内容,让我们一起来看看吧。
  1. import requests
  2. import readConfig as readConfig
  3. from common.Log import MyLog as Log
  4. localReadConfig = readConfig.ReadConfig()
  5. class ConfigHttp:
  6. def __init__(self):
  7.         global host, port, timeout
  8.         host = localReadConfig.get_http("baseurl")
  9.         port = localReadConfig.get_http("port")
  10.         timeout = localReadConfig.get_http("timeout")
  11. self.log = Log.get_log()
  12. self.logger = self.log.get_logger()
  13. self.headers = {}
  14. self.params = {}
  15. self.data = {}
  16. self.url = None
  17.         self.files = {}
  18. def set_url(self, url):
  19.         self.url = host + url
  20. def set_headers(self, header):
  21.         self.headers = header
  22. def set_params(self, param):
  23.         self.params = param
  24. def set_data(self, data):
  25.         self.data = data
  26. def set_files(self, file):
  27.         self.files = file
  28. # defined http get method
  29. def get(self):
  30. try:
  31.             response = requests.get(self.url, params=self.params, headers=self.headers, timeout=float(timeout))
  32. # response.raise_for_status()
  33. return response
  34.         except TimeoutError:
  35. self.logger.error("Time out!")
  36.             return None
  37. # defined http post method
  38. def post(self):
  39. try:
  40.             response = requests.post(self.url, headers=self.headers, data=self.data, files=self.files, timeout=float(timeout))
  41. # response.raise_for_status()
  42. return response
  43.         except TimeoutError:
  44. self.logger.error("Time out!")
  45. return None
复制代码
这里我们就挑重点来说吧。起首,可以看到,小编这次是用python自带的requests来举行接口测试的,相信故意的朋友已经看出来了,python+requests这个模式是很好用的,它已经帮我们封装好了测试接口的方法,用起来很方便。
这里呢,我就拿get和post两个方法来说吧。(平时用的最多的就是这两个方法了,其他方法,各人可以仿照着自行扩展)

get方法
接口测试中见到最多的就是get方法和post方法,其中,get方法用于获取接口的测试,说白了,就是说,使用get的接口,都不会对配景数据举行更改,而且get方法在传递参数后,url的格式是这样的:http://接口地址?key1=value1&key2=value2,是不是看起来很眼熟啊~(反正我看着它很眼熟~\(≧▽≦)/~啦啦啦),那我们要怎么使用它呢,请继续往下看。
对于requests提供的get方法,有几个常用的参数:
url:显而易见,就是接口的地址url啦
headers:定制哀求头(headers),例如:content-type = application/x-www-form-urlencoded
params:用于传递测试接口所要用的参数,这里我们用python中的字典形式(key:value)举行参数的传递。
timeout:设置接口连接的最大时间(超过该时间会抛出超时错误)
现在,各个参数我们已经知道是什么意思了,剩下的就是往内里填值啦,是不是机器式的应用啊,哈哈,小编我就是这样机器般的学习的啦~
举个栗子:​​​​​​​
  1. url=‘http://api.shein.com/v2/member/logout’
  2. header={‘content-type’:application/x-www-form-urlencoded}
  3. param={‘user_id’:123456,‘email’:123456@163.com}
  4. timeout=0.5
  5. requests.get(url, headers=header, params=param, timeout=timeout)
复制代码
post方法
与get方法雷同,只要设置好对应的参数,就可以了。下面就直接举个栗子,直接上代码吧:
  1. url=‘http://api.shein.com/v2/member/login’
  2. header={‘content-type’:application/x-www-form-urlencoded}
  3. data={‘email’:123456@163.com,‘password’:123456}
  4. timeout=0.5
  5. requests.post(url, headers=header, data=data, timeout=timeout)
复制代码
怎么样,是不是也很简单啊。这里我们需要说明一下,post方法中的参数,我们不在使用params举行传递,而是改用data举行传递了。哈哈哈,终于说完啦,下面我们来探(了)讨(解)下接口的返回值。
依然只说常用的返回值的操纵。
text:获取接口返回值的文本格式
json():获取接口返回值的json()格式
status_code:返回状态码(成功为:200)
headers:返回完整的哀求头信息(headers['name']:返回指定的headers内容)
encoding:返回字符编码格式
url:返回接口的完整url地址
以上这些,就是常用的方法啦,各人可自行取之。
关于失败哀求抛出异常,我们可以使用“raise_for_status()”来完成,那么,当我们的哀求发生错误时,就会抛出异常。
在这里提示下各位朋友,如果你的接口,在地址不精确的时候,会有相应的错误提示(有时也需要举行测试),这时,万万不能使用这个方法来抛堕落误,由于python自己在链接接口时就已经把错误抛出,那么,背面你将无法测试期望的内容。
而且程序会直接在这里当掉,以错误来计。(别问我怎么知道的,由于我就是测试的时候发现的)
好了。接口文件也讲完了,是不是感觉离成功不远了呢?嗯,如果各位已经看到了这里,那么恭喜各人,下面还有很长的路要走~哈哈哈,就是这么任性。
逐步地长叹一口吻,继续下面的内容。。。
快,我想学(看)习(看)common.py里的内容。​​​​​​​
  1. import os
  2. from xlrd import open_workbook
  3. from xml.etree import ElementTree as ElementTree
  4. from common.Log import MyLog as Log
  5. localConfigHttp = configHttp.ConfigHttp()
  6. log = Log.get_log()
  7. logger = log.get_logger()
  8. # 从excel文件中读取测试用例
  9. def get_xls(xls_name, sheet_name):
  10.     cls = []
  11. # get xls file's path
  12.     xlsPath = os.path.join(proDir, "testFile", xls_name)
  13. # open xls file
  14.     file = open_workbook(xlsPath)
  15. # get sheet by name
  16.     sheet = file.sheet_by_name(sheet_name)
  17. # get one sheet's rows
  18.     nrows = sheet.nrows
  19. for i in range(nrows):
  20. if sheet.row_values(i)[0] != u'case_name':
  21.             cls.append(sheet.row_values(i))
  22.     return cls
  23. # 从xml文件中读取sql语句
  24. database = {}
  25. def set_xml():
  26. if len(database) == 0:
  27.         sql_path = os.path.join(proDir, "testFile", "SQL.xml")
  28.         tree = ElementTree.parse(sql_path)
  29. for db in tree.findall("database"):
  30.             db_name = db.get("name")
  31. # print(db_name)
  32.             table = {}
  33. for tb in db.getchildren():
  34.                 table_name = tb.get("name")
  35. # print(table_name)
  36.                 sql = {}
  37. for data in tb.getchildren():
  38.                     sql_id = data.get("id")
  39. # print(sql_id)
  40.                     sql[sql_id] = data.text
  41.                 table[table_name] = sql
  42.             database[db_name] = table
  43. def get_xml_dict(database_name, table_name):
  44.     set_xml()
  45.     database_dict = database.get(database_name).get(table_name)
  46.     return database_dict
  47. def get_sql(database_name, table_name, sql_id):
  48.     db = get_xml_dict(database_name, table_name)
  49.     sql = db.get(sql_id)
  50. return sql
复制代码
上面就是我们common的两大重要内容了,什么?还不知道是什么吗?让我告诉你吧。


听起来会不会有点儿懵,小编刚学时也很懵,看文件就好理解了。
excel文件:


xml文件:

至于具体的方法,我就不再一点点讲授了,总以为各人都懂(小编刚学,望体谅),只是我个人需要具体记载,以后容易温习。
接下来,我们看看数据库和发送邮件吧(也可根据需要,不写该部门内容)
先看老朋友“数据库”吧。
小编这次使用的是MySQL数据库,所以我们就以它为例吧。
  1. import pymysql
  2. import readConfig as readConfig
  3. from common.Log import MyLog as Log
  4. localReadConfig = readConfig.ReadConfig()
  5. class MyDB:
  6.     global host, username, password, port, database, config
  7.     host = localReadConfig.get_db("host")
  8.     username = localReadConfig.get_db("username")
  9.     password = localReadConfig.get_db("password")
  10.     port = localReadConfig.get_db("port")
  11.     database = localReadConfig.get_db("database")
  12.     config = {
  13. 'host': str(host),
  14. 'user': username,
  15. 'passwd': password,
  16. 'port': int(port),
  17. 'db': database
  18.     }
  19. def __init__(self):
  20. self.log = Log.get_log()
  21. self.logger = self.log.get_logger()
  22. self.db = None
  23.         self.cursor = None
  24. def connectDB(self):
  25. try:
  26. # connect to DB
  27. self.db = pymysql.connect(**config)
  28. # create cursor
  29. self.cursor = self.db.cursor()
  30.             print("Connect DB successfully!")
  31.         except ConnectionError as ex:
  32.             self.logger.error(str(ex))
  33. def executeSQL(self, sql, params):
  34. self.connectDB()
  35. # executing sql
  36. self.cursor.execute(sql, params)
  37. # executing by committing to DB
  38. self.db.commit()
  39.         return self.cursor
  40. def get_all(self, cursor):
  41.         value = cursor.fetchall()
  42.         return value
  43. def get_one(self, cursor):
  44.         value = cursor.fetchone()
  45.         return value
  46. def closeDB(self):
  47. self.db.close()
  48.         print("Database closed!")
复制代码
这就是完整的数据库的文件啦。由于小编的需求对数据库的操纵不是很复杂,所以这些已基本满足要求啦。留意下啦,在此之前,请朋友们先把pymysql装起来!pymysql装起来!pymysql装起来!(重要的事变说三遍),安装的方法很简单,由于小编是使用pip来管理python包安装的,所以只要进入python安装路径下的pip文件夹下,实行以下命令即可:
  1. pip install pymysql
复制代码
哈哈哈,这样我们就可以利用python链接数据库啦~(鼓个掌,庆祝下)
小伙伴们发现没,在整个文件中,我们并没有出现具体的变量值哦,为什么呢?没错,由于前面我们写了config.ini文件,所有的数据库配置信息都在这个文件内哦,是不是感觉很方便呢,以后就算变动数据库了,也只要修改config.ini文件的内容就可以了,结合前面测试用例的管理(excel文件),sql语句的存放(xml文件),还有接下来我们要说的,businessCommon.py和存放具体case的文件夹,那么我们就已经将数据和业务分开啦,哈哈哈,想想以后修改测试用例内容,sql语句神马的工作,再也不消每个case都修改,只要改几个固定的文件,是不是顿时开心了呢?
回归上面的configDB.py文件,内容很简单,相信各人都能看得懂,就是连接数据库,实行sql,获取结果,最后关闭数据库,没有什么不一样的地方。
该谈谈邮件啦,你是不是也碰到过这样的标题:每次测试完之后,都需要给开辟一份测试报告。那么,对于我这样的懒人,是不愿意老是找人家开辟的,所以,我就想,每次测试完,我们可以让程序自己给开辟人员发一封email,告诉他们,测试已经结束了,并且把测试报告以附件的形式,通过email发送给开辟者的邮箱,这样岂不是爽哉!
所以,configEmail.py应运而生。当当当当……请看:
  1. import os
  2. import smtplib
  3. from email.mime.multipart import MIMEMultipart
  4. from email.mime.text import MIMEText
  5. from datetime import datetime
  6. import threading
  7. import readConfig as readConfig
  8. from common.Log import MyLog
  9. import zipfile
  10. import glob
  11. localReadConfig = readConfig.ReadConfig()
  12. class Email:
  13. def __init__(self):
  14.         global host, user, password, port, sender, title, content
  15.         host = localReadConfig.get_email("mail_host")
  16.         user = localReadConfig.get_email("mail_user")
  17.         password = localReadConfig.get_email("mail_pass")
  18.         port = localReadConfig.get_email("mail_port")
  19.         sender = localReadConfig.get_email("sender")
  20.         title = localReadConfig.get_email("subject")
  21.         content = localReadConfig.get_email("content")
  22. self.value = localReadConfig.get_email("receiver")
  23. self.receiver = []
  24. # get receiver list
  25. for n in str(self.value).split("/"):
  26. self.receiver.append(n)
  27. # defined email subject
  28.         date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  29. self.subject = title + " " + date
  30. self.log = MyLog.get_log()
  31. self.logger = self.log.get_logger()
  32.         self.msg = MIMEMultipart('mixed')
  33. def config_header(self):
  34. self.msg['subject'] = self.subject
  35. self.msg['from'] = sender
  36.         self.msg['to'] = ";".join(self.receiver)
  37. def config_content(self):
  38.         content_plain = MIMEText(content, 'plain', 'utf-8')
  39.         self.msg.attach(content_plain)
  40. def config_file(self):
  41. # if the file content is not null, then config the email file
  42.         if self.check_file():
  43.             reportpath = self.log.get_result_path()
  44.             zippath = os.path.join(readConfig.proDir, "result", "test.zip")
  45. # zip file
  46.             files = glob.glob(reportpath + '\*')
  47.             f = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED)
  48. for file in files:
  49.                 f.write(file)
  50.             f.close()
  51.             reportfile = open(zippath, 'rb').read()
  52.             filehtml = MIMEText(reportfile, 'base64', 'utf-8')
  53.             filehtml['Content-Type'] = 'application/octet-stream'
  54.             filehtml['Content-Disposition'] = 'attachment; filename="test.zip"'
  55.             self.msg.attach(filehtml)
  56. def check_file(self):
  57.         reportpath = self.log.get_report_path()
  58. if os.path.isfile(reportpath) and not os.stat(reportpath) == 0:
  59. return True
  60. else:
  61.             return False
  62. def send_email(self):
  63. self.config_header()
  64. self.config_content()
  65. self.config_file()
  66. try:
  67.             smtp = smtplib.SMTP()
  68.             smtp.connect(host)
  69.             smtp.login(user, password)
  70.             smtp.sendmail(sender, self.receiver, self.msg.as_string())
  71.             smtp.quit()
  72. self.logger.info("The test report has send to developer by email.")
  73.         except Exception as ex:
  74.             self.logger.error(str(ex))
  75. class MyEmail:
  76.     email = None
  77.     mutex = threading.Lock()
  78. def __init__(self):
  79.         pass
  80.     @staticmethod
  81.     def get_email():
  82. if MyEmail.email is None:
  83.             MyEmail.mutex.acquire()
  84.             MyEmail.email = Email()
  85.             MyEmail.mutex.release()
  86.         return MyEmail.email
  87. if __name__ == "__main__":
  88.     email = MyEmail.get_email()
复制代码
这里就是完整的文件内容了,不外惋惜的是,小编我碰到一个标题,至今未解,在这里提出,希望大神给出解决办法!跪求啦!
标题:使用163免费邮箱服务器举行邮件的发送,但是,每次发送邮件,都会被163邮件服务器退信,抛出的错误码是:554
官方说明如下:


但是,however,but……小编在整合email进本框架之前写的发送email的小demo是可以正常发送邮件的。这个标题困扰着我,目前仍没有解决,望大神见教。
离成功不远了,简单说明下HTMLTestRunner.py文件,这个文件呢,也不是小编写的,小编只是它的搬运工,哈哈哈,这个文件是从网上下载的,大神写好的,用于生成html格式的测试报告,什么?想知道生成测试报告的样子?好,这就满足好奇的你:


看上去不错吧,嗯,智慧的你们,也可以自己去探索下这个文件,修改修改,变成你自己的style哦~
好了,重头戏来了,就是我们的runAll.py啦。请看主角登场。
这是我们整个框架运行的入口,上面内容完成后,这是最后一步啦,写完它,我们的框架就算是完成了。(鼓掌,撒花~)​​​​​​​
  1. import unittest
  2. import HTMLTestRunner
  3. def set_case_list(self):
  4.         fb = open(self.caseListFile)
  5. for value in fb.readlines():
  6.             data = str(value)
  7. if data != '' and not data.startswith("#"):
  8.                 self.caseList.append(data.replace("\n", ""))
  9.         fb.close()
  10. def set_case_suite(self):
  11.         self.set_case_list()
  12.         test_suite = unittest.TestSuite()
  13.         suite_model = []
  14. for case in self.caseList:
  15.             case_file = os.path.join(readConfig.proDir, "testCase")
  16.             print(case_file)
  17.             case_name = case.split("/")[-1]
  18.             print(case_name+".py")
  19.             discover = unittest.defaultTestLoader.discover(case_file, pattern=case_name + '.py', top_level_dir=None)
  20.             suite_model.append(discover)
  21. if len(suite_model) > 0:
  22. for suite in suite_model:
  23. for test_name in suite:
  24.                     test_suite.addTest(test_name)
  25. else:
  26. return None
  27.         return test_suite
  28. def run(self):
  29. try:
  30.             suit = self.set_case_suite()
  31. if suit is not None:
  32.                 logger.info("********TEST START********")
  33.                 fp = open(resultPath, 'wb')
  34.                 runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='Test Report', description='Test Description')
  35.                 runner.run(suit)
  36. else:
  37.                 logger.info("Have no case to test.")
  38. except Exception as ex:
  39.             logger.error(str(ex))
  40. finally:
  41.             logger.info("*********TEST END*********")
  42. # send test report by email
  43. if int(on_off) == 0:
  44.                 self.email.send_email()
  45. elif int(on_off) == 1:
  46.                 logger.info("Doesn't send report email to developer.")
  47. else:
  48.                 logger.info("Unknow state.")
复制代码
上面我贴出了runAll内里的重要部门,起首我们要从caselist.txt文件中读取需要实行的case名称,然后将他们添加到python自带的unittest测试集中,最后实行run()函数,实行测试集。
终于呢,整个接口主动化框架已经讲完了,各人是不是看明白了呢?什么?之前的之前贴出的目录结构中的文件还有没说到的?
嘿嘿,,,相信不消小编多说,各人也大概知道了,剩下文件夹的作用了。嗯~思索万千,还是决定简单谈谈吧。直接上图,简单明白:

   
result文件夹会在初次实行case时生成,并且以后的测试结果都会被生存在该文件夹下,同时每次测试的文件夹都是用系统时间命名,内里包罗了两个文件,log文件和测试报告。

testCase文件夹下,存放我们写的具体的测试case啦,上面这些就是小编写的一些。留意喽,所有的case名称都要以test开头来命名哦,这是由于,unittest在举行测试时会主动匹配testCase文件夹下面所有test开头的.py文件

testFile文件夹下,放置我们测试时用来管理测试用例的excel文件和用于数据库查询的sql语句的xml文件哦。
最后就是caselist.txt文件了,就让你们瞄一眼吧:

凡是没有被注释掉的,都是要被实行的case名称啦。在这里写上你要实行的case名称就可以啦。
呼~长舒一口吻,终于完成了整个过程,嗯,相信对峙看下来的你们肯定会有所劳绩的。
最后:下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取【保证100%免费】

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权势巨子的解答,刷完这一套面试资料相信各人都能找到满足的工作。

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战堆栈,这个堆栈也伴随上万个测试工程师们走过最艰难的路程,希望也能资助到你!



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4