四.unittest接口自动化框架介绍

少壮不努力123 / 2024-03-10 / 原文

一. unittest常用校验方法介绍
   1.unittest模板基本概念
     unittest是python内置的单元测试框架,具备编写用例、组织用例、执行用例、输出报告等自动化框架的条件。使用unittest前需要了解该框架的五个概念:
即test case, test suite, testLoader,test runner, test fixture。
test case  :一个完整的测试单元,执行该测试单元可以完成对某一个问题的验证,完整体现在:测试前环境准备(setUp),执行测试代码(run),及测试后环境还原(tearDown);
test suite  :多个测试用例的集合,测试套件或测试计划;
testLoader  :加载TestCase到TestSuite中的,其中loadTestsFrom__()方法用于寻找TestCase,并创建它们的实例,然后添加到TestSuite中,返回TestSuite实例;
test runner :执行测试用例,并将测试结果保存到TextTestResult实例中,包括运行了多少测试用例, 成功了多少,失败了多少等信息;
test fixture:一个测试用例的初始化准备及环境还原,主要是setUp() 和 setDown()方法;
    2.unittest模板基本介绍
     1.简单的unittest的使用
 #首先导入unittest
import unittest

class testUnittestOne(unittest.TestCase):

     #编写测试用例,方法名必须以test开头
     def test_equals(self):
         self.assertEquals(1,1,msg="相等")

 #执行测试用例
if __name__ == '__main__':
    unittest.main()
View Code

    2.testCase多个之间的执行顺序,按照测试用例的方法名字母进行排序执行的;每条用例执行前都会执行一下setUp方法,用例执行后都还会在执行一遍tearDown方法

import unittest

class testUnittestTwo(unittest.TestCase):
#测试用例初始化方法setUp
    def setUp(self):
        print("开始执行测试用例")

#测试用例后置方法tearDown
    def tearDown(self):
        print("执行完测试用例")

    def test_case1(self):
        print("执行case1")
        self.assertEqual(1,1,msg="1等于1")

    def test_aase2(self):
        print("执行case2")
        self.assertEqual(1, 2, msg="1不等于2")

if __name__ == '__main__':
    unittest.main()
View Code
执行结果:
   
   3.setUpClass、tearDownClass类方法分别是该测试类执行前的初始化方法和后置方法
 import unittest

 class testUnittestTwo(unittest.TestCase):
     #测试用例初始化方法setUp
     @classmethod
     def setUpClass(self):
         print("开始执行测试用例")

     #测试用例后置方法tearDown
     @classmethod
     def tearDownClass(self):
         print("执行完测试用例")

     def test_case1(self):
         print("执行case1")
         self.assertEqual(1,1,msg="1等于1")

     def test_aase2(self):
         print("执行test_aase2")
         self.assertEqual(1, 2, msg="1不等于2")

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

执行结果:

  3.unittest模板常用校验方法

 

 

二. unittest接口参数化及用例集介绍

   1.unittest参数化
 import unittest
 import requests
 import parameterized  # 数据参数化需要导入该模块
 import HTMLTestRunner

 class LoginTest(unittest.TestCase):
     url = "http://api.nnzhp.cn/api/user/login"

    # 测试数据进行参数化
     @parameterized.parameterized.expand([
         ["niuhanyang", "aA123456"],
         ["niuhanyang", "aA1234567"],
         ["niuhanyang", "aA1234568"]
     ])
     def test_login(self, username, password):
         data = {"username": username, "passwd": password}
         re = requests.post(self.url, data).text
         self.assertIn("userId", re, "包含userId")


 if __name__ == '__main__':
     # 把测试用例放在测试集合中
     suite = unittest.makeSuite(LoginTest)
     f = open("report.html", "wb")
     # 生成测试报告,需要先导入HTMLTestRunner模板,放在当前目录下或python第三方模板安装的site_package文件夹下
     runner = HTMLTestRunner.HTMLTestRunner(f, description="baogao", title="")
     runner.run(suite)
     f.close()
View Code

执行结果:

 2.unittest通过读取文件内容进行参数化

定义user.txt文件,文件每行定义三个参数,逗号进行分割;

 

 import unittest
 import parameterized
 import requests
 import HTMLTestRunner


 class TestParameFile(unittest.TestCase):
     url = 'http://api.nnzhp.cn/api/user/login'

     """
     通过文件进行参数化
     """

     def getDataForFile(fileName):
         data = []
         with open(fileName, encoding="utf-8") as fw:
             for line in fw:
                 line = line.strip()
                 if line:
                     data.append(line.split(","))
         return data

     @parameterized.parameterized.expand(getDataForFile("users.txt"))
     def test_login(self, username, password, check):
         # 发送接口请求
         re = requests.post(self.url, {"username": username, "passwd": password}).text
         self.assertIn(check, re, "没有返回%s" % check)


 if __name__ == "__main__":
     # 生成测试用例套件
     testSuit = unittest.makeSuite(TestParameFile)

     f = open("testParameFile.html", "wb")
     Runner = HTMLTestRunner.HTMLTestRunner(f, title="测试报告", description="测试报告详情")
     Runner.run(testSuit)
     f.close()
View Code

执行结果:

  3.unittest多个用例集运行
创建case文件夹,在case文件夹下定义多个测试用例类

 

 import unittest
 import HTMLTestRunner
 import time
 import BeautifulReport


 class RunManyTestCase(unittest.TestCase):

     def runTestCase(self):
         # 将测试用例加载到caseSuite中
         caseSuite = unittest.defaultTestLoader.discover("case", "*")
         f = open("manyReport%s.html" % (time.strftime("%y%m%d")), "wb")
         runCase = HTMLTestRunner.HTMLTestRunner(f, title="用例集报告", description="xxx系统测试报告")
         runCase.run(caseSuite)
         f.close()

     def runTestCaseReport(self):
         # 将测试用例加载到caseSuite中
         caseSuite = unittest.defaultTestLoader.discover("case", "*")
         bf = BeautifulReport.BeautifulReport(caseSuite)
         bf.report(description='查找测试用例的', filename='discover%s.html' % (time.time()))


 if __name__=="__main__":
     c = RunManyTestCase()
     c.runTestCase()
     c.runTestCaseReport()
View Code

  4.unittest通过HTMLTestRunner进行生成报告

 import unittest
 import HTMLTestRunner
 import time
 import BeautifulReport


 class RunManyTestCase(unittest.TestCase):

     def runTestCase(self):
         # 将测试用例加载到caseSuite中
         caseSuite = unittest.defaultTestLoader.discover("case", "*")
         f = open("manyReport%s.html" % (time.strftime("%y%m%d")), "wb")
         runCase = HTMLTestRunner.HTMLTestRunner(f, title="用例集报告", description="xxx系统测试报告")
         runCase.run(caseSuite)
         f.close()

     def runTestCaseReport(self):
         # 将测试用例加载到caseSuite中
         caseSuite = unittest.defaultTestLoader.discover("case", "*")
         bf = BeautifulReport.BeautifulReport(caseSuite)
         bf.report(description='查找测试用例的', filename='discover%s.html' % (time.time()))


 if __name__=="__main__":
     c = RunManyTestCase()
     c.runTestCase()
View Code

执行结果:

 5.unittest通过BeautifulReport进行生成报告

 import unittest
 import HTMLTestRunner
 import time
 import BeautifulReport


 class RunManyTestCase(unittest.TestCase):

     def runTestCase(self):
         # 将测试用例加载到caseSuite中
         caseSuite = unittest.defaultTestLoader.discover("case", "*")
         f = open("manyReport%s.html" % (time.strftime("%y%m%d")), "wb")
         runCase = HTMLTestRunner.HTMLTestRunner(f, title="用例集报告", description="xxx系统测试报告")
         runCase.run(caseSuite)
         f.close()

     def runTestCaseReport(self):
         # 将测试用例加载到caseSuite中
         caseSuite = unittest.defaultTestLoader.discover("case", "*")
         # 生成测试报告,需要先导入BeautifulReport模板,放在当前目录下或python第三方模板安装的site_package文件夹下
         bf = BeautifulReport.BeautifulReport(caseSuite)
         bf.report(description='查找测试用例的', filename='discover%s.html' % (time.time()))


if __name__=="__main__":
     c = RunManyTestCase()
     c.runTestCaseReport()
View Code

 执行结果:

 附件:HTMLTestRunner.py文件和BeautifulReport.zip压缩吧

 

6.unittest创建有关联关系的接口
import unittest
import parameterized


class Case(unittest.TestCase):


    def login(self,userid):
        return userid

    @parameterized.parameterized.expand([
        [222],
        [333]
    ])
    def test_login(self,userid):
        "ss"
        userid=self.login(userid)

        return self.assertEqual(userid,222,'成功')

suite=unittest.makeSuite(Case)

import BeautifulReport.BeautifulReport

bf=BeautifulReport.BeautifulReport(suite)
bf.report(description="测试报告",filename='关联关系的.html')
View Code
三. unittest封装接口自动化框架
1.需求分析
    utp接口自动化框架:
        a.接口自动化测试用例放在cases目录下且case开头进行命名,涉及到有关联关系的接口可以先定义基类
        b.接口自动化测试用例需要与接口分离,因此需要进行参数化,数据放在datas目录下
        c.查询所有测试接口进行运行,运行成功后发送邮件
 
2.代码编写
    a.先分别创建bin、cases、configs、datas、libs、logs、reports文件夹,bin目录进行存放程序主入口,cases目录下
存放接口测试用例;configs目录下进行存放配置文件;datas目录下进行存放接口测试数据;libs目录下进行存放常用功能;logs目录下进行存放日志文件;reports进行存放接口自动化测试报告

     b.libs文件夹下定义toos.py

import os

import jsonpath
from configs.Settings import T0,CC,EMAIL_INFO,LOG,DATAS_PATH
import traceback,time,yagmail

def get_value(d,k):
    # 通过jsonpath.jsonpath来取字典中key所对应的值
    result=jsonpath.jsonpath(d,'$..%s'%k)
    # 如果取到了返回第一个值,否则返回空字符串
    if result:
        return result[0]
    return ''

def send_email(pass_count,fail_count,file_name):
    LOG.debug("开始发送报告了,文件名是%s"%file_name)
    content='''
各位好:
    本次接口自动化测试结果如下,总共运行%s条用例,通过%s条,失败【%s】条。
    详情请查看附件。
    '''%((pass_count+fail_count),pass_count,fail_count)

    subject='%s-接口测试报告'%time.strftime("%Y-%m-%d %H%M%S")

    email=yagmail.SMTP(**EMAIL_INFO,encoding="GBK")

    try:
        email.send(to=T0,cc=CC,subject=subject,contents=content,attachments=file_name)
    except Exception as e:
        LOG.error("发送报告失败,具体失败原因是%s"%traceback.format_exc())
    else:
        LOG.debug("报告发送成功")

def get_data_from_text(file_name):
    """获取参数化数据"""
    data=[]
    file_name=os.path.join(DATAS_PATH,file_name)
    with open(file_name,encoding='utf-8') as fr:
        for line in fr:
            line=line.strip()
            if line:
                data.append(line.split(","))
    return data

def get_data_from_excel(file_name):
    """获取参数化数据"""
    pass


def get_data_from_db(file_name):
    """获取参数化数据"""
    pass

def get_data_from_redis(file_name):
    """获取参数化数据"""
    pass
View Code

    c.configs文件夹下定义Settings.py文件

import os


# 发送邮件
EMAIL_INFO={
    "user":"13424210282@163.com",
    "password":"HLXWWGTUWGNAAAEA",
    "host":"smtp.163.com",
}
# 邮件接收人
T0=["974219141@qq.com"]
# 邮件抄送人
CC=['751462075@qq.com']

# 接口请求url地址配置
host_map={
    "fat":"http://127.0.0.1:8787",
    "uat":"",
    "pro":""
}
default="fat"

HOST=host_map.get(default)

# 自动化项目父目录
BASE_PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 测试用例目录
CASE_PATH=os.path.join(BASE_PATH,'cases')
# 日志文件目录
LOG_PATH=os.path.join(BASE_PATH,"logs",'utp.log')

import nnlog
LOG=nnlog.Logger(LOG_PATH)
# 测试报告目录
REPORT_PATH=os.path.join(BASE_PATH,'reports')

# 查询用例
DATAS_PATH=os.path.join(BASE_PATH,'datas')
View Code
    d.cases文件夹下定义case_login.py文件(没有关联关系)
1.没关联关系的接口
import unittest
import parameterized
from libs.tools import get_data_from_text
import requests
from configs.Settings import HOST
from urllib.parse import urljoin

class CaseTestLogin(unittest.TestCase):
    # 拼接接口请求url
    url=urljoin(HOST,"/login")

    # 进行参数,通过get_data_from _text获取login.txt文件
    @parameterized.parameterized.expand(get_data_from_text("login.txt"))
    def test_login(self,user,password,check):
        data={"username":user,"password":password}
        headers={"Content-Type":"application/json"}
        # 发送接口请求
        r=requests.post(self.url,json=data,headers=headers).text
        # 校验check参数的值是否在接口返回的字符串中
        self.assertIn(check,r,"%s在%s中"%(check,r))
View Code

2.有关联关系的接口,先在BaseCase.py文件中定义基类Base_Case

import unittest
import requests
from configs.Settings import HOST
from urllib.parse import urljoin
from libs.tools import get_value

class Base_Case(unittest.TestCase):

    def login(self,user,password,check):
        data = {"username": user, "password": password}
        headers = {"Content-Type": "application/json"}
        # 发送接口请求
        r = requests.post(urljoin(HOST,"/login"), json=data, headers=headers)
        # 校验
        self.assertIn(check, r.text, "%s在%s中" % (check, r.text))
        # 获取接口请求返回的tokenId并进行返回
        tokenId=get_value(r.json(),'tokenId')
        return tokenId
View Code

 在定义case_pay.py文件中Case_Pay类继承Base_Case类

import unittest

import requests

from cases import BaseCase
from configs.Settings import HOST
from urllib.parse import urljoin
from parameterized import parameterized
from libs.tools import get_data_from_text

class Case_Pay(BaseCase.Base_Case):

    @parameterized.expand(get_data_from_text("pay.txt"))
    def test_pay(self,user,password,check,money):
        """支付成功"""
        tokenId=self.login(user,password,check)
        data={"username":user,"money":money}
        headers={"tokenId":tokenId}
        r=requests.post(urljoin(HOST,"/pay"),json=data,headers=headers)
        self.assertIn("支付成功",r.text,)
View Code

    e.datas文件夹下定义login.txt和pay.txt文件

    f.bin目录下定义程序运行start.py文件

import sys,os
import time

BASE_PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,BASE_PATH)

import unittest
import BeautifulReport
from libs.tools import send_email
from configs.Settings import REPORT_PATH,CASE_PATH

def run():
    suite=unittest.defaultTestLoader.discover(CASE_PATH,"case*.py")
    bf=BeautifulReport.BeautifulReport(suite)
    filename="utp报告%s.html"%(time.strftime("%Y%m%d%H%M%S"))
    report_path=os.path.join(REPORT_PATH,filename)
    bf.report(description="utp测试报告",filename=filename,log_path=REPORT_PATH)
    send_email(bf.success_count,bf.failure_count,report_path)

if __name__ == '__main__':
    run()
View Code

最后运行bin目录下的start.py文件,可以正常看到测试报告