接口自动化环境搭建-Python Request + Unittest

文章目录

  • 前言
  • 一、前期准备
  • 二、搭建环境
    • 1. 创建项目目录
    • 2. 创建一个cases目录,管理所有的case
    • 3. 找一个测试接口,编写测试脚本
    • 4. 抽离公共方法 - 发送请求
    • 5. 抽离测试数据 - 读取Excel
    • 6. 抽离基本数据 - 读取配置文件
    • 7. 生成测试报告
    • 8. 自动发送测试报告到邮箱
  • 总结


前言

使用python搭建一个接口自动化的框架,主要实现的功能如下:

  • 在Excel中编写接口测试用例,代码读取去执行
  • 执行接口测试用例后, 自动生成测试报告
  • 生成测试报告后, 自动发送邮件到邮箱

下面案例可供参考

一、前期准备

  • python3安装
  • Excel中编写接口测试用例

二、搭建环境

1. 创建项目目录

	demoauto

接口自动化环境搭建-Python Request + Unittest_第1张图片

2. 创建一个cases目录,管理所有的case

这个目录可以存放所有的测试脚本(针对测试用例的断言)

接口自动化环境搭建-Python Request + Unittest_第2张图片

3. 找一个测试接口,编写测试脚本

例子:

https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=XXXXXX

这是一个公共接口,可以随便使用

接口自动化环境搭建-Python Request + Unittest_第3张图片

  1. 在cases文件目录下,创建一个py文件,以test开头
  2. 编写测试脚本

接口自动化环境搭建-Python Request + Unittest_第4张图片

import unittest
import requests

class TestMobileTelSegment(unittest.TestCase):

    def sendRequests(self):
        self.url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm"
        self.method = "get"
        self.params = "tel=157XXXXXXX87"
        res = requests.request(self.method,self.url,params =self.params)
        print(res.text)
        return res.text

    def test01case(self):
        res = self.sendRequests()
        expect_result = '''__GetZoneResult_ = {
                                mts:'15XXXXX',
                                province:'云南',
                                catName:'中国移动',
                                telString:'15XXXXX987',
                                areaVid:'3XX5',
                                ispVid:'3XXX39',
                                carrier:'云南移动'
                            }'''
        self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))


if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestMobileTelSegment("test01case"))
    runner = unittest.TextTestRunner(verbosity=3)
    runner.run(suite)

小结:

1、Unittest是python自带的模块,拥有断言的功能。使用Unittest作为测试断言,必须引入unittest模块,并让测试类继承Unittest.Testcase

2、执行测试用例可以把所有测试用例添加到一个suite里,然后去执行

接口自动化环境搭建-Python Request + Unittest_第5张图片
如果在这个类中再编写一个test02case,则只需再runner前一行,再添加一句:suite.addTest(TestMobileTelSegment(“test02case”))

4. 抽离公共方法 - 发送请求

当编写大量测试脚本的时候,每一个接口都要用到发送请求,所以可以把发送请求的接口抽离出来,编写为一个公共方法
  1. 创建common目录,存放所有的公共类
  2. 编写脚本
    接口自动化环境搭建-Python Request + Unittest_第6张图片
    sendrequest.py
import requests as rq


class SendRequest:
    def send_request(self, url, method, params="", headers=""):
        res = rq.request(method, url, params=params, headers=headers)
        return res.text

修改test_mobile_tel_segment.py

import unittest
import requests
from demoauto.common.sendrequest import SendRequest

class TestMobileTelSegment(unittest.TestCase):

    def test01case(self):
        #测试的数据
        url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm"
        method = "get"
        params = "tel=15XXXXXXX87"

        #发送请求
        res = SendRequest().send_request(url, method, params)

        #断言
        expect_result = '''__GetZoneResult_ = {
                                mts:'1XXXXX9',
                                province:'云南',
                                catName:'中国移动',
                                telString:'15XXXXXX7',
                                areaVid:'30515',
                                ispVid:'32XXXX9',
                                carrier:'云南移动'
                            }'''
        self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))


if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestMobileTelSegment("test01case"))
    runner = unittest.TextTestRunner(verbosity=3)
    runner.run(suite)

小结:

1、提取了公共方法后,使用时需要引入

5. 抽离测试数据 - 读取Excel

用Excel编写测试用例,代码读取测试数据、请求信息后执行

接口自动化环境搭建-Python Request + Unittest_第7张图片

  1. 创建一个目录,存放excel的用例
  2. 公共方法:读取Excel
    接口自动化环境搭建-Python Request + Unittest_第8张图片
import os

import openpyxl as ox
#获取当前路径:到common结束
#path = os.path.abspath(os.path.dirname(__file__))
#path = os.getcwd()

#获取当前路径的上一层路径:到demoauto
path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))

class ReadExcel():
    def get_workbook(self, filename):
        #测试用例实际的路径
        xlsPath = os.path.join(path, 'testfile', filename)
        print(xlsPath)
        # 打开测试用例
        f = ox.load_workbook(xlsPath)
        #获取当前要操作的sheet对象

        return f

    def get_title(self, filename):
        f = self.get_workbook(filename)
        sheet = f.active
        #读取标题行
        for row in sheet.iter_rows(max_row=1):
            title_row = [cell.value for cell in row]

        self.close_file(f)

        return title_row

    def get_data(self, filename):
        f = self.get_workbook(filename)
        sheet = f.active
        #读取正文内容
        arr = []
        for row in sheet.iter_rows(min_row=2):
            row_data  = [cell.value for cell in row]
            arr.append(row_data)

        self.close_file(f)

        return arr

    #获取全部case内容
    def get_all_cases(self) -> list:
        arr = self.get_data("autotestcase.xlsx")
        return arr

    def get_case_by_module_name(self, modulename):
        arr = self.get_data("autotestcase.xlsx")
        caseinfo = []
        for i in range(len(arr)):
            if arr[i][1] == modulename:
                caseinfo.append(arr[i])

        return caseinfo

    def get_case_by_case_name(self, casename):
        arr = self.get_data("autotestcase.xlsx")
        caseinfo = None
        for i in range(len(arr)):
            if arr[i][2] == casename:
                caseinfo = arr[i]

        return caseinfo


    def close_file(self, f):
        f.close()

#测试,最后运行项目时,需要注释这段代码
if __name__ == '__main__':
    re = ReadExcel()
    data = re.get_case_by_case_name('mobile_tel_segment_normalTel')
    print(data)

  1. 修改test_mobile_tel_segment.py文件,将写死的数据换成excel中读取的数据
import unittest
import requests
from demoauto.common.sendrequest import SendRequest
from demoauto.common.readexcel import ReadExcel

class TestMobileTelSegment(unittest.TestCase):

    def getResult(self, case_name):
        #从Excel中读取数据,需要传入casename,才指定要获取哪条用例
        #返回的是一个list
        caseinfo = ReadExcel().get_case_by_case_name(case_name)
        url = "https://tcc.taobao.com" + caseinfo[3]
        method = caseinfo[5]
        params = caseinfo[4]

        # 发送请求
        res = SendRequest().send_request(url, method, params)

        #返回实际结果和预期结果
        return  res, caseinfo[6]

    def test01case(self):
        #断言
        res, expect_result = self.getResult("mobile_tel_segment_normalTel")
        self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))

    def test02case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_lessLengthTel")
        self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))

    def test03case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_moreLengthTel")
        self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))

    def test04case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_characterException")
        self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))



if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestMobileTelSegment("test01case"))
    suite.addTest(TestMobileTelSegment("test02case"))
    suite.addTest(TestMobileTelSegment("test03case"))
    suite.addTest(TestMobileTelSegment("test04case"))
    runner = unittest.TextTestRunner(verbosity=3)
    runner.run(suite)

运行结果
接口自动化环境搭建-Python Request + Unittest_第9张图片
小结:
1、操作excel需要使用到python的openpyxl模块

6. 抽离基本数据 - 读取配置文件

程序中有一些不经常变动的数据,比如系统的baseurl,端口号,用户名,密码,数据库连接使用到的一些数据,可以抽离出来放在配置文件中,或者登录接口返回的Token会在后续接口中使用,也可以存储在配置文件中,会使代码更干净整洁

  1. 将baseurl和端口号抽离到配置文件中,创建一个cfg目录存放配置文件
  2. 编写读取配置文件的公共类

接口自动化环境搭建-Python Request + Unittest_第10张图片

import os
import configparser
#获取当前路径的上层路径:到demoauto
path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
#获取config文件的路径
config_path = os.path.join(path, 'cfg\config.ini')
print(config_path)

#调用读取配置文件的方法
config = configparser.ConfigParser()
config.read(config_path, encoding='utf-8')

class ReadConfig():
    def get_baseInfo(self):
        protocol = config.get('HTTP', 'scheme')
        baseurl = config.get('HTTP', 'baseurl')
        port = config.get('HTTP', 'port')
        return protocol+'://'+baseurl+':'+port

#测试
if __name__ == '__main__':
    data = ReadConfig().get_baseInfo()
    print(data)

  1. 修改test_mobile_tel_segment.py文件
import unittest
import requests
from demoauto.common.sendrequest import SendRequest
from demoauto.common.readexcel import ReadExcel
from demoauto.common.readconfig import ReadConfig

class TestMobileTelSegment(unittest.TestCase):

    def getResult(self, case_name):
        #从配置文件读取baseurl
        baseurl = ReadConfig().get_baseInfo()
        #从Excel中读取数据,需要传入casename,才指定要获取哪条用例
        #返回的是一个list
        caseinfo = ReadExcel().get_case_by_case_name(case_name)
        url = baseurl + caseinfo[3]
        method = caseinfo[5]
        params = caseinfo[4]

        # 发送请求
        res = SendRequest().send_request(url, method, params)

        #返回实际结果和预期结果
        return  res, caseinfo[6]

    def test01case(self):
        #断言
        res, expect_result = self.getResult("mobile_tel_segment_normalTel")
        self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))

    def test02case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_lessLengthTel")
        self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))

    def test03case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_moreLengthTel")
        self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))

    def test04case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_characterException")
        self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))



if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestMobileTelSegment("test01case"))
    suite.addTest(TestMobileTelSegment("test02case"))
    suite.addTest(TestMobileTelSegment("test03case"))
    suite.addTest(TestMobileTelSegment("test04case"))
    runner = unittest.TextTestRunner(verbosity=3)
    runner.run(suite)

小结:
1、读写配置文件需要引入configparser模块

7. 生成测试报告

  1. 创建生成测试报告的py文件,放在common目录下吧
  2. 创建一个存放测试报告的目录,测试报告为Report.html
  3. 将运行测试用例的脚本抽离到一个类里

1、生成测试报告的py文件,我在网上找了个大神写的靠谱的模版
https://github.com/findyou/HTMLTestRunnerCN/tree/dev

接口自动化环境搭建-Python Request + Unittest_第11张图片

接口自动化环境搭建-Python Request + Unittest_第12张图片
这里选的是中文版本的报告,复制下来放在createreport.py中

创建一个目录result,存放测试报告
接口自动化环境搭建-Python Request + Unittest_第13张图片

demoauto目录下创建执行所有case的类,把刚才test_mobile_tel_segment.py中的main方法放过来
接口自动化环境搭建-Python Request + Unittest_第14张图片

import unittest
from demoauto.cases.test_mobile_tel_segment import TestMobileTelSegment
from demoauto.common.createreport import HTMLTestReportCN
import os

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestMobileTelSegment("test01case"))
    suite.addTest(TestMobileTelSegment("test02case"))
    suite.addTest(TestMobileTelSegment("test03case"))
    suite.addTest(TestMobileTelSegment("test04case"))
    # runner = unittest.TextTestRunner(verbosity=3)
    # runner.run(suite)

    # 获取当前路径:到demoauto
    path = os.path.abspath(os.path.dirname(__file__))
    filePath = os.path.join(path, 'result\\Report.html')

    fp = open(filePath, 'wb')

    #需要传入Report的路径
    runner = HTMLTestReportCN(
        stream=fp,
        title='{ AutoTest Report }',
        # description='',
        # tester="Findyou"
    )
    runner.run(suite)

这里发现一个问题,test_mobile_tel_segment.py文件中断言assertTrue写得有问题,结果与预期值等时都会返回通过,因为assertTrue的参数是一个表达式,所以更正为如下:



    def test01case(self):
        #断言
        res, expect_result = self.getResult("mobile_tel_segment_normalTel")
        self.assertTrue(res.replace("\n","")== expect_result.replace("\n",""))
        print(res)
        print(expect_result)

    def test02case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_lessLengthTel")
        self.assertTrue(res.replace("\n", "")==expect_result.replace("\n", ""))
        print(res)
        print(expect_result)

    def test03case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_moreLengthTel")
        self.assertTrue(res.replace("\n", "")==expect_result.replace("\n", ""))

    def test04case(self):
        # 断言
        res, expect_result = self.getResult("mobile_tel_segment_characterException")
        self.assertTrue(res.replace("\n", "")==expect_result.replace("\n", ""))

运行runallcase.py,Report.html生成代码,浏览器打开该文件。最后测试结果:

接口自动化环境搭建-Python Request + Unittest_第15张图片
页面会显示test_mobile_tel_segment中print的内容
接口自动化环境搭建-Python Request + Unittest_第16张图片

8. 自动发送测试报告到邮箱

  1. 创建公共类,发送邮件
  2. 修改runallcase.py文件,加入自动发送邮件代码

接口自动化环境搭建-Python Request + Unittest_第17张图片

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import os

class SendEmail():
    def send_mail(self):
        # 邮件服务器
        smtpserver = 'smtp.163.com'
        # 发件人和密码
        sender = '[email protected]'
        password = 'xxxxxxxx'
        # password = 'xxxxxxxxx'
        # 接收人
        receiver = '[email protected]'
        # 邮件主题
        subject = u'自动化测试报告'
        # 获取当前路径的上层路径:到demoauto
        path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
        # 获取config文件的路径
        file_path = os.path.join(path, 'result\\Report.html')
        print(file_path)
        # ----------------------------------------------------------
        # 连接登录邮箱
        server = smtplib.SMTP(smtpserver, 25)
        server.login(sender, password)
        # ----------------------------------------------------------
        # 构建邮件附件
        msg = MIMEMultipart()
        part_attach1 = MIMEApplication(open(file_path, 'rb').read())  # 打开附件
        part_attach1['Content-Type'] = 'application/octet-stream'
        part_attach1.add_header('Content-Disposition', 'attachment', filename=file_path)  # 为附件命名
        msg.attach(part_attach1)

        text = MIMEText("哈哈哈,我给你发送邮件啦","plain",'utf-8')
        msg['From'] = sender
        msg['To'] = receiver
        msg['Subject'] = Header(subject, 'utf-8').encode()
        msg.attach(text)
        # ----------------------------------------------------------
        # 发送邮件
        server.sendmail(sender, [receiver], msg.as_string())
        server.quit()
        print("发送成功!")

    # if __name__ == '__main__':
    #     send_mail()

修改runallcase.py

import unittest
from demoauto.cases.test_mobile_tel_segment import TestMobileTelSegment
from demoauto.common.createreport import HTMLTestReportCN
import os
from demoauto.common.sendmail import SendEmail

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestMobileTelSegment("test01case"))
    suite.addTest(TestMobileTelSegment("test02case"))
    suite.addTest(TestMobileTelSegment("test03case"))
    suite.addTest(TestMobileTelSegment("test04case"))
    # runner = unittest.TextTestRunner(verbosity=3)
    # runner.run(suite)

    # 获取当前路径:到demoauto
    path = os.path.abspath(os.path.dirname(__file__))
    filePath = os.path.join(path, 'result\\Report.html')

    fp = open(filePath, 'wb')

    #需要传入Report的路径
    runner = HTMLTestReportCN(
        stream=fp,
        title='{ AutoTest Report }',
        # description='',
        # tester="Findyou"
    )
    runner.run(suite)
    SendEmail().send_mail()

小结:
1、可能会遇到SMTPAuthenticationError: (550, b’User has no permission’)
或smtplib.SMTPAuthenticationError: (535, b’Error: authentication failed’),解决方法如下:

1、开启授权:
https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac2cda80145a1742516
接口自动化环境搭建-Python Request + Unittest_第18张图片
接口自动化环境搭建-Python Request + Unittest_第19张图片

2、代码里把邮箱的password设置为这个授权码

总结

搭建这个框架用了一个多星期,不熟悉python的一些语法,靠百度搭建起来了。遇到了很多问题,一步步解决了,也算有所收获。其中还有很多改进的地方。后面有耐心再改吧。

1、邮箱的信息从配置文件中读取
2、测试用例封装成类

完整代码上传到csdn,需要修改一下自己的邮箱

你可能感兴趣的:(python自动化测试,python,软件测试,unittest)