IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 2.2unittest框架自动化测试 -> 正文阅读

[开发测试]2.2unittest框架自动化测试

作者:recommend-item-box type_blog clearfix

框架概括

? unittest是python 的单元测试框架,自动化测试

? unittest 单元测试提供了创建测试用例,测试套件以及批量执行的方案, unittest 在安装pyhton 以后就直接自带 了,直接import unittest 就可以使用。

? 作为单元测试的框架, unittest 也是可以对程序最小模块的一种敏捷化的测试。在自动化测试中,我们虽然不需要做白盒测试,但是必须需要知道所使用语言的单元测试框架。利用单元测试框架,创建一个类,该类继承unittest 的TestCase,这样可以把每个case看成是一个最小的单元, 由测试容器组织起来,到时候直接执行,同时引入测试报告。

在这里插入图片描述

  • test fixture:初始化和清理测试环境,比如创建临时的数据库,文件和目录等,其中 setUp() 和 setDown()
    是最常用的方法
  • test case:单元测试用例,TestCase 是编写单元测试用例最常用的类
  • test suite:单元测试用例的集合,TestSuite 是最常用的类
  • test runner:执行单元测试
  • test report:生成测试报告

? 在main方法中的runner = unittest.TextTestRunner(verbosity=?)中或者unittest.main(verbosity=?)中可以增加verbosity参数,例如unittest.main(verbosity=2)在主函数中,直接调用main() ,在main中加入verbosity=2 ,这样测试的结果就会显示的更加详细。这里的verbosity 是一个选项, 表示测试结果的信息复杂度,有三个值:
0 ( 静默模式): 你只能获得总的测试用例数和总的结果比如总共100个失败,20 成功80
1 ( 默认模式): 非常类似静默模式只是在每个成功的用例前面有个“ . ” 每个失败的用例前面有个“F”
2 ( 详细模式): 测试结果会显示每个测试用例的所有相关的信息

面试题

  1. 测试固件用的什么方法

    setUP() 进行测试前的初始化工作

    tearDown() 进行测试后的清理工经

  2. 测试方法的命名?

    要以 test_ 开头才能识别

  3. 测试方法的执行顺序

    ascll码表的顺序执行,0-1,A-Z ,a-z这样的顺序

  4. 测试套件的组织方式

    addTest:把测试脚本的方法都添加到测试套件中

    makeSuite和TestLoader:把整个测试脚本的方法都添加到测试用例中

    discover 把某个文件夹下,以设定格式命名的所有脚本的所有测试方法都添加到套件中。

    使用@unittest.skip(“skipping”)注解来使这个测试方法跳过测试运行

  5. 测试报告的生成

    HTMLTestRunner

    步骤:

    1. 使用sys语句得到父路径
    curpath = sys.path[0]
    print(sys.path)
    print(sys.path[0])
    # 路径不存在就创建一个
    if not os.path.exists(curpath + '/resultreport'):
        os.makedirs(curpath + '/resultreport')
    
    1. 文件命名的生成
    now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))
    print(time.time())
    print(time.localtime(time.time()))
    # 构造文件名
    filename = curpath + '/resultreport/' + now + 'resultreport.html'
    
    1. 生成测试报告
    with open(filename, 'wb') as fp:
        runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title="测试报告",description="用例测试情况", verbosity=2)
    
  6. 断言的使用

  7. ddt数据驱动的使用

单元测试用例

testMybaidu1

import unittest
from selenium import webdriver
import os
import time


class MyBaidu(unittest.TestCase):
    def setUp(self):
        print("开始测试setUp(): ")
        self.driver = webdriver.Chrome()
        self.url = "https://www.baidu.com/"
        self.driver.implicitly_wait(2)

    def tearDown(self):
        print("结束测试tearDown(): ")
        self.driver.quit()

    def test_new(self):
        driver = self.driver
        driver.get(self.url)
        driver.implicitly_wait(3)
        print(driver.title)
        driver.find_element_by_link_text("新闻").click()
        time.sleep(3)

    def test_baidusearch(self):
        driver = self.driver
        driver.get(self.url)
        time.sleep(3)
        title = driver.title
        driver.find_element_by_id("kw").send_keys("北辙南辕")
        driver.find_element_by_id("su").click()
        self.assertTrue(title == "百度一下,你就知道", msg="hello is not equal!")
        time.sleep(6)

    if __name__ == "__main__":
        unittest.main(verbosity=2)

testMybaidu2

import unittest
from selenium import webdriver
import os
import time


class MyBaidu(unittest.TestCase):
    def setUp(self):
        print("开始测试setUp(): ")
        self.driver = webdriver.Chrome()
        self.url = "https://www.baidu.com/"
        self.driver.implicitly_wait(2)

    def tearDown(self):
        print("结束测试tearDown(): ")
        self.driver.quit()

    def test_new(self):
        driver = self.driver
        driver.get(self.url)
        driver.implicitly_wait(3)
        driver.find_element_by_link_text("直播").click()
        print(driver.title)
        time.sleep(3)

    def test_baidusearch(self):
        driver = self.driver
        driver.get(self.url)
        time.sleep(3)
        title = driver.title
        driver.find_element_by_id("kw").send_keys("南辕北辙")
        driver.find_element_by_id("su").click()
        self.assertTrue(title == "百度一下,你就知道", msg="hello is not equal!")
        time.sleep(6)

    if __name__ == "__main__":
        unittest.main(verbosity=2)

构建测试套件

? 完整的单元测试很少执行一个测试用例,通常都需要编写多个测试用例才能对软件功能进行比较完整的测试,我们将这些相关的测试用例称为一个测试用例集,在unittest中使用TestSuite来表示。

addTest()方法

? unittest 模块中提供了TestSuite 类来生成测试套件,使用该类的构造函数可以生成一个测试套件的实例,该类提供了addTest来把每个测试用例加入到测试套件中。

? 缺点:

  • 测试时需要导入所有测试用例的py文件,每新增一个就必须导入一个。

  • addTest需要增加所有的testcase用例,如果一个文件里面有10个casename需要增加10次。

import unittest
import testMybaidu1
import testMybaidu2


def createsuite():
    # 将测试用例加入到测试(容器)套件中进行
    # addTest手动加入测试用例到测试套件的方法
    suite = unittest.TestSuite()
    suite.addTest(testMybaidu1.MyBaidu("test_new"))
    suite.addTest(testMybaidu1.MyBaidu("test_baidusearch"))

    suite.addTest(testMybaidu2.MyBaidu("test_new"))
    suite.addTest(testMybaidu2.MyBaidu("test_baidusearch"))
    return suite


if __name__ == '__main__':
    # 创建了一个测试套件
    suite = createsuite()
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

makesuit()方法

? 在unittest 框架中提供了makeSuite() 的方法,makeSuite可以实现把测试用例类内所有的测试case组成的测试套件TestSuite ,unittest 调用makeSuite的时候,只需要把测试类名称传入即可。

? 缺点:

  • 测试时需要导入所有测试用例的py文件,每新增一个就必须导入一个。
import unittest
import testMybaidu1
import testMybaidu2


def createsuite():
    # 使用makesuit方法
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(testMybaidu1.MyBaidu))
    suite.addTest(unittest.makeSuite(testMybaidu2.MyBaidu))
    return suite


if __name__ == '__main__':
    # 创建了一个测试套件
    suite = createsuite()
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

TestLoader()方法

? TestLoader 用于创建类和模块的测试套件,一般的情况下,使TestLoader().loadTestsFromTestCase(TestClass)来加载测试类

import unittest
import testMybaidu1
import testMybaidu2


def createsuite():
    # 将测试用例加入到测试(容器)套件中进行

    # TestLoader
    suite1 = unittest.TestLoader().loadTestsFromTestCase(testMybaidu1.MyBaidu)
    suite2 = unittest.TestLoader().loadTestsFromTestCase(testMybaidu2.MyBaidu)
    suite3 = unittest.TestSuite([suite1, suite2])
    return suite3


if __name__ == '__main__':
    # 创建了一个测试套件
    suite = createsuite()
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

discover()的应用

? discover 是通过递归的方式到其子目录中从指定的目录开始, 找到所有测试模块并返回一个包含它们对象的TestSuite ,然后进行加载与模式匹配唯一的测试文件,discover 参数分别为discover(dir,pattern,top_level_dir=None)

import unittest


def createsuite():
    # 将测试用例加入到测试(容器)套件中进行
    # discover
    
    discover = unittest.defaultTestLoader.discover("./",pattern="test*.py",top_level_dir=None)
    print(discover)
    return discover


if __name__ == '__main__':
    # 创建了一个测试套件
    suite = createsuite()
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

用例的执行顺序

? unittest 框架默认加载测试用例的顺序是根据ASCII 码的顺序,数字与字母的顺序为: 09,AZ,a~z 。所以, TestAdd 类会优先于TestBdd 类被发现,test_aaa() 方法会优先于test_ccc() 被执行。

? 对于测试目录与测试文件来说, unittest 框架同样是按照这个规则来加载测试用例。

addTest()方法按照增加顺序来执行。

忽略用例使其不执行

? 使用@unittest.skip(u’The function was canceled, neglects to perform thecase’))注解

错误处理

except:

def test_baidu(self):
    driver = self.driver
    driver.get(self.url)
    driver.implicitly_wait(3)
    print(driver.title)
    try:
        self.assertEqual(u"dddd百度一下,你就知道", driver.title)
    except:
        self.saveScreenShot(driver, "hao.png")
    time.sleep(5)//在错误处理流程进行截图

unittest断言

? 自动化的测试中, 对于每个单独的case来说,一个case的执行结果中, 必然会有期望结果与实际结果, 来判断该case是通过还是失败,

? 在unittest 的库中提供了大量的实用方法来检查预期值与实际值, 来验证case的结果, 一般来说, 检查条件大体分为等价性, 逻辑比较以及其他, 如果给定的断言通过, 测试会继续执行到下一行的代码, 如果断言失败, 对应的case测试会立即停止或者生成错误信息( 一般打印错误信息即可) ,但是不要影响其他的case执行。

序号断言方法断言描述
1assertEqual(arg1, arg2, msg=None)验证arg1=arg2,不等则fail
2assertNotEqual(arg1, arg2, msg=None)验证arg1 != arg2, 相等则fail
3assertTrue(expr, msg=None)验证expr是true,如果为false,则fail
4assertFalse(expr,msg=None)验证expr是false,如果为true,则fail
5assertIs(arg1, arg2, msg=None)验证arg1、arg2是同一个对象,不是则fail
6assertIsNot(arg1, arg2, msg=None)验证arg1、arg2不是同一个对象,是则fail
7assertIsNone(expr, msg=None)验证expr是None,不是则fail
8assertIsNotNone(expr, msg=None)验证expr不是None,是则fail
9assertIn(arg1, arg2, msg=None)验证arg1是arg2的子串,不是则fail
10assertNotIn(arg1, arg2, msg=None)验证arg1不是arg2的子串,是则fail
11assertIsInstance(obj, cls, msg=None)验证obj是cls的实例,不是则fail
12assertNotIsInstance(obj, cls, msg=None)验证obj不是cls的实例,是则fail

通过selenium IDE来添加断言

在这里插入图片描述

HTML报告生成

HTMLTestRunner.HTMLTestRunner

import HTMLTestRunnerimport osimport sysimport timeimport unittestdef createstuite():    discovers = unittest.defaultTestLoader.discover("./", pattern="test*.py", top_level_dir=None)    print(discovers)    return discoversif __name__ == '__main__':    curpath = sys.path[0]    print(sys.path)    print(sys.path[0])    # 路径不存在就创建一个    if not os.path.exists(curpath + '/resultreport'):        os.makedirs(curpath + '/resultreport')    # 2.测试要执行很多次,命名很可能会重复    now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))    print(time.time())    print(time.localtime(time.time()))    # 构造文件名    filename = curpath + '/resultreport/' + now + 'resultreport.html'    # 打开 HTML 文件 ,wb的方式写入    with open(filename, 'wb') as fp:        runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u"测试报告",                                               description=u"用例测试情况", verbosity=2)        suite = createstuite()        runner.run(suite)

错误截图生成

driver.get_screenshot_as_file()使用这个API进行截图

except:进行错误处理

import osimport timeimport unittestfrom selenium import webdriverclass Baidu1(unittest.TestCase):    def setUp(self) -> None:        self.driver = webdriver.Chrome()        self.driver.implicitly_wait(5)        self.url = "https://www.baidu.com/"        self.verificationErrors = []        self.accept_next_alert = True    def tearDown(self) -> None:        self.driver.quit()        self.assertEqual([], self.verificationErrors)    def test_baidusearch(self):        driver = self.driver        driver.get(self.url)        driver.find_element_by_id("kw").clear()        driver.find_element_by_id("kw").send_keys("大鱼海棠")        driver.find_element_by_id("su").click()        time.sleep(3)    def test_baidu(self):        driver = self.driver        driver.get(self.url)        driver.implicitly_wait(3)        print(driver.title)        try:            self.assertEqual(u"dddd百度一下,你就知道", driver.title)        except:            self.saveScreenShot(driver, "hao.png")        time.sleep(5)//在错误处理流程进行截图    # 截图的函数    def saveScreenShot(self, driver, filename):        if not os.path.exists("./image"):            os.makedirs("./image")        now = time.strftime("%Y%m%d-%H%M%S", time.localtime(time.time()))        driver.get_screenshot_as_file("./image/" + now + "-" + filename)        time.sleep(2)if __name__ == '__main__':    unittest.main(verbosity=2)

数据驱动

? 需要多次执行一个案例,比如baidu搜索,分别输入中文、英文、数字等进行搜索,这时候需要编写3个案例吗?有
没有版本一次运行?
? python 的unittest 没有自带数据驱动功能。所以如果使用unittest,同时又想使用数据驱动,那么就可以使用DDT
来完成。

dd.ddt
装饰类,也就是继承自TestCase的类。
ddt.data
装饰测试方法。参数是一系列的值。
ddt.file_data

  • 装饰测试方法。参数是文件名。文件可以是json 或者 yaml类型。

  • 注意,如果文件以”.yml”或者”.yaml”结尾,ddt会作为yaml类型处理,其他所有文件都会作为json文件处理。

  • 如果文件中是列表,每个列表的值会作为测试用例参数,同时作为测试用例方法名后缀显示。

  • 如果文件中是字典,字典的key会作为测试用例方法的后缀显示,字典的值会作为测试用例参数。

unpack

? 传递的是复杂的数据结构时使用。比如使用元组或者列表,添加unpack之后,ddt会自动把元组或者列表对应到多个参数上。字典也可以这样处理。下面看一个样例:

单个参数数据

? 使用@data()注解进行参数替换

两个或者两个以上参数

? 使用@unpack注解进行解绑

txt文件读取

? 首先自己构造方法读取文件,将数据转化为数组后,同样使用@data()注解进行参数替换

# @data(['Lisa', u"Lisa_百度搜索"], [u"双笙", u"7798双笙_百度搜索"], [u"双笙2", u"双笙2_百度搜索"])
@data(*getCsv('test_baidu_data.txt'))
# ([周迅, 周迅_百度搜索], [张国荣, 张国荣111_百度搜索], [张一山,张一三_百度搜索])
@unpack
def test_baidu2(self, value, execptdata):
    driver = self.driver
    driver.get(self.base_url + "/")
    driver.find_element_by_id("kw").clear()
    driver.find_element_by_id("kw").send_keys(value)
    driver.find_element_by_id("su").click()
    time.sleep(2)
    # 判断搜索网页的title和我们期望的是否一致
    self.assertEqual(execptdata, driver.title, msg="和预期搜索结果不一致!")
    print(execptdata)
    print(driver.title)
    time.sleep(2)

json格式文件

? 使用file_data()注解进行读取

@file_data('D:\\pythonProject1\\pythonProject\\bit\\test\\unittest框架\\练习\\data\\test_baidu_data.json')
def test_baidu2(self, value):
    print(value)
    testdata, execptdata = tuple(value.strip().split(":"))
    driver = self.driver
    driver.get(self.base_url + "/")
    driver.find_element_by_id("kw").clear()
    driver.find_element_by_id("kw").send_keys(testdata)
    driver.find_element_by_id("su").click()
    time.sleep(2)
    # 判断搜索网页的title和我们期望的是否一致
    self.assertEqual(execptdata, driver.title, msg="和预期搜索结果不一致!")
    print(execptdata)
    print(driver.title)
    time.sleep(2)

总示例:

# -*- coding: utf-8 -*-

import csv
import sys
import time
import unittest

from ddt import ddt, unpack, data
from selenium import webdriver


def getCsv(file_name):
    rows = []
    path = sys.path[0]

    with open(path + '/data/' + file_name, 'rt') as f:
        readers = csv.reader(f, delimiter=',', quotechar='|')
        next(readers, None)
        for row in readers:
            temprows = []
            for i in row:
                temprows.append(i)
            rows.append(temprows)
        return rows

@ddt
class Baidu1(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(30)
        self.base_url = "http://www.baidu.com/"
        self.driver.maximize_window()
        self.verificationErrors = []
        self.accept_next_alert = True

    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

    # @file_data('test_baidu_data.json')
    # @unpack
    @data("王凯", "Lisa", "特朗普", "蒋欣")
    @unittest.skip("skipping")
    def test_baidu1(self, value):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys(value)
        driver.find_element_by_id("su").click()
        time.sleep(3)

    # json格式读取
    # @unittest.skip("skipping")
    # @file_data('D:\\pythonProject1\\pythonProject\\bit\\test\\unittest框架\\练习\\data\\test_baidu_data.json')
    # def test_baidu2(self, value):
    #     print(value)
    #     testdata, execptdata = tuple(value.strip().split(":"))
    #     driver = self.driver
    #     driver.get(self.base_url + "/")
    #     driver.find_element_by_id("kw").clear()
    #     driver.find_element_by_id("kw").send_keys(testdata)
    #     driver.find_element_by_id("su").click()
    #     time.sleep(2)
    #     # 判断搜索网页的title和我们期望的是否一致
    #     self.assertEqual(execptdata, driver.title, msg="和预期搜索结果不一致!")
    #     print(execptdata)
    #     print(driver.title)
    #     time.sleep(2)



    # @data(['Lisa', u"Lisa_百度搜索"], [u"双笙", u"7798双笙_百度搜索"], [u"双笙2", u"双笙2_百度搜索"])
    @data(*getCsv('test_baidu_data.txt'))
    # ([周迅, 周迅_百度搜索], [张国荣, 张国荣111_百度搜索], [张一山,张一三_百度搜索])
    @unpack
    def test_baidu2(self, value, execptdata):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys(value)
        driver.find_element_by_id("su").click()
        time.sleep(2)
        # 判断搜索网页的title和我们期望的是否一致
        self.assertEqual(execptdata, driver.title, msg="和预期搜索结果不一致!")
        print(execptdata)
        print(driver.title)
        time.sleep(2)


if __name__ == '__main__':
    unittest.main(verbosity=1)
    # getpy("test_baidu_data.json")
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-08-17 15:41:40  更:2021-08-17 15:42:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/28 0:21:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码