我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python unittest框架

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python unittest框架

    unittest模块提供了单元测试的组件,方便开发人员进行自测。

    一、unittest中的重要概念:

    测试用例:测试用例对象是最小的测试单位,针对指定的输入来测试期待的输出。由类TestCase的派生类或FunctionTestCase类来创建的。

    测试固件:代表了测试相关的准备和清除工作,比如在一个测试进行之前需要创建数据库连接,测试结束之后需要关闭数据库连接。测试固件是在TestCase子类中进行重载的setUp和tearDown函数实现的。每个测试用例执行前后都会自动执行setUp和tearDown方法。另外如果setUp执行抛出异常,则忽略未执行的测试用例,测试结束

    测试套件:包含一组测试用例,一起执行。同时,也可以包含其他测试套件。可以通过TestSuite类创建对象来添加测试用例;也可以使用unittest提供的TestLoader来自动将指定的测试用例收集到一个自动创建的TestSuit对象中。

    测试驱动:主要负责执行测试,并反馈测试结果。TestRunner对象存在一个run()方法,它接收一个TestCase对象或TestSuit对象作为参数,返回测试的结果对象(TestResult)

    

    二、编写最简单的测试代码

    下面是一个数学操作的类,包含加法和除法操作。并提供了对应的单元测试代码,从这个例子上,我们学习一些unittest基本的功能:

#exam.py文件提供了供测试的示例类
#coding: utf-8

class operator(object):
    def __init__(self, a, b):
        self.a = a 
        self.b = b 
    
    def add(self):
        return self.a + self.b 
    
    def divide(self):
        return self.a / self.b     


#test.py文件提供了通过unittest构建的测试代码    
#coding:utf-8

from exam import operator
import unittest

class TestOperator(unittest.TestCase):
    
    def setUp(self):               #test fixture
        self.oper = operator(10,0)
    def test_add(self):            #test case
        self.assertEqual(self.oper.add(), 10, u"加法基础功能不满足要求")

    def test_divide(self):
        self.assertRaises(ZeroDivisionError, self.oper.divide())
    
    #def tearDown(self):
        #pass
        
if __name__ == "__main__":
    unittest.main(verbosity=2)

运行test.py文件,即可见到下面的输出:

test_add (__main__.TestOperator) ... ok
test_divide (__main__.TestOperator) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
  • 测试类需要继承自TestCase

  • 测试方法默认是通过前缀test来标示的,所以在测试类中添加非test前缀的辅助方法并不会影响测试用例的搜集。

  • 测试方法一般通过TestCase提供的assert*方法来判断结果是否符合预期。

  • 每个测试实例都仅包含一个test*方法,即上面的代码会创建两个测试实例,每个测试实例包含一个test*的方法

  • unittest.main提供了命令行的接口,启动测试,并反馈测试结果。其中的参数verbosity指详细显示测试结果。

    想象:main中的逻辑应该是挺复杂的,需要构建test实例对象?需要找到那些是用于测试的方法?需要统计测试结果?等等一些我们还没认识到的东西?

    解决这些困惑的方法很直接,让我们调试main函数吧,,come on!

    我们可以看到main代表一个命令行接口类:我们可以通过命令行的方式执行测试,这和通过代码中的main启动测试时一样的过程。

main = TestProgram                            #
...

class TestProgram(object):                    #命令行接口类
    """A command-line program that runs a set of tests; this is primarily
       for making test modules conveniently executable.
    """

    运行main(),即无传参调用__init__.py来构建一个对象。

def __init__(self, module='__main__', defaultTest=None, argv=None,
                    testRunner=None, testLoader=loader.defaultTestLoader,
                    exit=True, verbosity=1, failfast=None, catchbreak=None,
                    buffer=None):
    。。。。
    self.exit = exit
    self.failfast = failfast
    self.catchbreak = catchbreak
    self.verbosity = verbosity
    self.buffer = buffer
    self.defaultTest = defaultTest
    self.testRunner = testRunner
    self.testLoader = testLoader
    self.progName = os.path.basename(argv[0])  #以上是初始化工作
    self.parseArgs(argv)                       #解析参数argv,并加载test
    self.runTests()                            #运行test,并反馈结果

    在执行__init__.py的过程中,首先进行一些初始化工作,即传入main的参数或是通过命令行添加的参数影响了unittest内部的某些特性,比如例子中的verbosity代表了测试结果输出的详细度,如果被设置为1,或者不设置,结果中将不会显示具体的testcase名称,大家可以自己验证一下;

    接下来,进入self.parseArgs(argv),让我们看下它做了什么:

def parseArgs(self, argv):
        if len(argv) > 1 and argv[1].lower() == 'discover':
            self._do_discovery(argv[2:])
            return
        。。。。
        try:
            options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
            for opt, value in options:
                if opt in ('-h','-H','--help'):
                    self.usageExit()
                if opt in ('-q','--quiet'):
                    self.verbosity = 0
                if opt in ('-v','--verbose'):    #命令行参数-v即代表了main参数verbosity
                    self.verbosity = 2
                if opt in ('-f','--failfast'):
                    if self.failfast is None:
                        self.failfast = True
            。。。。                     #以上是从argv中读取参数,并适当对初始化值进行修改
            self.createTests()          #创建测试实例,返回他们的集合-suit对象(测试套件)              
            。。。。

    首先,参数如果是‘discover’则进入另一个分支,是关于自动发现的功能,后面会讲到。

    然后开始解析argv,这里的argv首选传入main的argv参数,如果为None,则取命令行执行该脚本时传递的sys.argv。可以看到命令行传递的sys.argv参数和传递到main的其他参数是相互替代的,这就达到了通过命令行传参启动和通过main代码传参启动,效果是一样的。

    接下来调用createTests来创建测试实例,我们继续看下:

def createTests(self):
        if self.testNames is None:
            self.test = self.testLoader.loadTestsFromModule(self.module)
        else:
            self.test = self.testLoader.loadTestsFromNames(self.testNames,
                                                           self.module)

    仅从方法的名字就可以看出,创建Tests就是在模块或是具体的test方法上加载。加载的过程主要就是搜集测试方法,创建TestCase实例,并返回包含有这些case的TestSuit对象,后面会详细看下。

    至此,创建测试实例完成,接着就回到__init__中执行self.runTest()来真正启动测试了:

def runTests(self):
        if self.catchbreak:          #-c表示运行过程中捕捉CTRL+C异常
            installHandler()
        if self.testRunner is None:  
            self.testRunner = runner.TextTestRunner      #runner默认是TextTestRunner
        if isinstance(self.testRunner, (type, types.ClassType)):
            try:
                testRunner = self.testRunner(verbosity=self.verbosity,
                                             failfast=self.failfast,
                                             buffer=self.buffer)
            except TypeError:
                # didn't accept the verbosity, buffer or failfast arguments
                testRunner = self.testRunner()
        else:
            # it is assumed to be a TestRunner instance
            testRunner = self.testRunner         #以上部分是构建testRunner对象,即测试驱动
        self.result = testRunner.run(self.test)  #就像上面讲到的由runner的run方法启动测试
        if self.exit:
            sys.exit(not self.result.wasSuccessful())

    从代码中可以看出,测试由testRunner实例通过run函数来启动,默认的testRunner是unittest提供的TextTestRunner。这个run方法设计很亮眼,感兴趣的同志可以深入看下,里面涉及了__call__和__iter__的用法并且巧妙结合。

    main函数简单的调用即代替我们完成了基本的测试功能,其内部可是复杂滴很哦。


    三、命令行接口

    上面我们看到了,main和命令行接口根本就是同一个类,只是这个类做了两种执行方式的兼容。

使用python -m unittest -h可以查看帮助命令,其中python -m unittest discover是命令行的另一分支,后面讨论,它也有自己的帮助命令,即也在后面加上-h

    具体的命令可自行研究。


    四、测试发现

    测试发现指,提供起始目录,自动搜索该目录下的测试用例。与loadTestsFromModule等相同的是都由TestLoader提供,用来加载测试对象,返回一个TestSuit对象(包裹了搜索到的测试对象)。不同的是,测试发现可以针对一个给定的目录来搜索。

    也可以通过上面提到的命令行来自动发现:python -m unittest discover **

    可以指定下面的参数:-s 起始目录(.)  -t 顶级目录(.)  -p 测试文件的模式匹配

    过程简要描述如下:目录:顶级目录/起始目录,该目录应该是一个可导入的包,即该目录下应该提供__init__.py文件。在该目录下。使用-p模式匹配test用例所在的文件,然后在从这些文件中默认通过‘test’前缀来搜集test方法构建test实例,最终返回一个test实例集合的suit对象。

    

    五、一些好用的修饰器

    unittest支持跳过某些测试方法甚至整个测试类,也可以标志某些方法是期待的不通过,这样如果不通过的话就不会列入failure的计数中。等等这些都是通过装饰器来实现的。让我们把本文开篇的基础的例子重用一下,将test.py改成下面这样:

#test.py文件提供了通过unittest构建的测试代码    
#coding:utf-8

from exam import operator
import unittest,sys

class TestOperator(unittest.TestCase):
    
    def setUp(self):               #test fixture
        self.oper = operator(10,0)
    
    @unittest.skip("I TRUST IT")           #
    def test_add(self):            #test case
        self.assertEqual(self.oper.add(), 10, u"加法基础功能不满足要求")
        
    @unittest.skipIf(sys.platform == 'win32', "it just only run in Linux!")
    def test_divide(self):
        self.assertRaises(ZeroDivisionError, self.oper.divide())
    
    #def tearDown(self):
        #pass
        
if __name__ == "__main__":
    unittest.main(verbosity=2)

 再次运行之后,结果如下:

test_add (__main__.TestOperator) ... skipped 'I TRUST IT'
test_divide (__main__.TestOperator) ... skipped 'it just only run in Linux!'

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK (skipped=2)

    unittest.skipUnless(condition, reason):如果condition为真则不会跳过该测试

    unittest.expectedFailure():将该test标志为期待的失败。之后如果该测试不符合预期或引发异常,则不会计入失败数

    

    一直很崇拜装饰器,不如就在此领略一下大神的风采,让我们看看到底装饰器是否必要,主要应用场景是什么。就先拿里面最简单的skip来看吧:

def skip(reason):
    """
    Unconditionally skip a test.
    """
    def decorator(test_item):
        if not isinstance(test_item, (type, types.ClassType)):
            @functools.wraps(test_item)
            def skip_wrapper(*args, **kwargs):
                raise SkipTest(reason)
            test_item = skip_wrapper

        test_item.__unittest_skip__ = True
        test_item.__unittest_skip_why__ = reason
        return test_item
    return decorator

    可以看出,如果该skip装饰器修饰测试类时,直接添加__unittest_skip__属性即可,这会在实例运行中判断。如果修饰测试方法时,会将修饰的方法替代为一个触发SkipTest异常的方法,并同样给修饰的方法添加__unittest_skip__属性。

    添加的属性在测试实例运行时会用到,在TestCase类提供的run方法中作判断:

 if (getattr(self.__class__, "__unittest_skip__", False) or
            getattr(testMethod, "__unittest_skip__", False)):
            # If the class or method was skipped.
            try:
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                self._addSkip(result, skip_why)
            finally:
                result.stopTest(self)
            return

    如果测试方法或其所属的类存在__unittest_skip__属性为真,则会跳过该测试。通过上面我们看出,实例运行时只会检查__unittest_skip__属性值而并不会抓取SkipTest异常,那为什么skip装饰器中要对修饰的函数进行替换的操作呢?

    想不通,注释掉if块,程序依然可以运行的好好的,留个疑点吧!

    

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python unittest框架

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python unittest框架

unittest模块提供了单元测试的组件,方便开发人员进行自测。    一、unittest中的重要概念:    测试用例:测试用例对象是最小的测试单位,针对指定的输入来测试期待的输出。由类TestCase的派生类或FunctionTest
2023-01-31

Python中的Unittest框架的用法

本篇内容主要讲解“Python中的Unittest框架的用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python中的Unittest框架的用法”吧!  Unittest  1.环境  Un
2023-06-02

python中unittest框架的作用是什么

这篇文章给大家介绍python中unittest框架的作用是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。python是什么意思Python是一种跨平台的、具有解释性、编译性、互动性和面向对象的脚本语言,其最初的设
2023-06-14

Python自动化测试框架之unittest使用详解

unittest是Python自动化测试框架之一,提供了一系列测试工具和接口,支持单元测试、功能测试、集成测试等多种测试类型。unittest使用面向对象的思想实现测试用例的编写和管理,可以方便地扩展和定制测试框架,支持多种测试结果输出格式
2023-05-18

python自动化测试框架pytest和unittest的区别是什么

这篇文章给大家介绍python自动化测试框架pytest和unittest的区别是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、用例设计规则1.unittest(1)测试类必须继承unittest.TestCa
2023-06-02

python unittest初探

待测试的类:class Request:    url = ""    method = ""    paras = {}    def __init__(self,url):        self.url = url        se
2023-01-31

Python模块——unittest 单

unittest是python单元测试框架,又叫做PyUnit。之所以称为框架是它代替开发人员完成了一些调用、IO等与单元测试无直接关系的支撑代码,让开发人员可以专注与测试用例的编写,简化单元测试工作。 单元测试是一种基本的,由开发人员(而
2023-01-31

Python 单元测试(unittest

项目的整体结构可以参考“软件目录开发规范”,这里单说测试目录。一般都是在项目里单独创建一个测试目录,目录名就是“tests”。关于目录的位置,一种建议是,在项目名(假设项目名是Foo)的一级子目录下创建二级子目录 “Foo/foo/test
2023-01-31

Python Web 框架 Sanic

1.操作系统CentOS 7.2 X642.安装系统包gcc-c++zlib-developenssl-devel3.update python 3.51).安装PythonPython-3.5.2.tgz./configuremakema
2023-01-31

Python Web框架Tornado

Python Web框架Tornado的异步处理代码示例Tornado是一个轻量级但高性能的Python web框架,与另一个流行的Python web框架Django相比,tornado不提供操作数据库的ORM接口及严格的MVC开发模式,
2023-01-31

python Tornado框架 入

Tornado介绍Tornado 是一个Python web框架和异步网络库 起初由 FriendFeed 开发. 通过使用非阻塞网络I/O, Tornado 可以支持上万级的连接,处理 长连接, WebSockets, 和其他 需要与每个
2023-01-31

spark入门框架+python

目录:简介pysparkIPython Notebook安装配置spark编写框架:首先开启hdfs以及yarn1 sparkconf2 sparkcontext3 RDD(核心)4 transformation(核心)         
2023-01-31

Python 前端框架【Bootstra

Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web 开发更加快捷。使用bootstrap组件构
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录