接着上一篇讲到测试方法的执行。unittest测试框架有几种运行方式呢?我学到的是六种。如果你看源码能力足够的话(我是看完后头就疼了,能力有限,但还好大致搞清楚了),点开main.py就发现,都写在初始化方法里了。入参这里给大家做个简单的解释。

按住ctrl键,点击main

在unittest框架中TextTestRunner表示________ unittest的方法_python


在unittest框架中TextTestRunner表示________ unittest的方法_运行方式_02


defaultTest=None, 待测试用例的名称,默认是所有,可以运行指定测试用例,传入形式可以是字符串或者是序列,例如:defaultTest=[“类.测试用例”]

testRunner=None, 测试运行器,TextTestRunner 默认运行出来的结果是文本格式

testLoader=loader.defaultTestLoader, 指定使用默认的测试用例加载器

verbosity=1, 类似于命令行-v, 0(简洁的模式),1(正常的模式),2(详细的模式)

以下参数不重要,了解即可。

exit=True, 是否在用例完成后结束python程序

failfast=None, 失败的时候是否终止测试

argv=None, 接受外部参数

catchbreak=None,

buffer=None, 是否捕获输出流

warnings=None 是否显示警告信息

tb_locals=False

接下来就简单举例说明
创建一个jx_01_case.py文件,内容如下:

import unittest

class BusinessCase(unittest.TestCase):

    def test_01(self):
        print("测试用例1执行成功")

    def test_02(self):
        print("测试用例2执行成功")

    def test_03(self):
        print("测试用例3执行成功")

    def test_10(self):
        print("测试用例10执行成功")

1.第一种运行方式。所有用例都执行,这也是最基础的。

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

第二种运行方式。指定执行某条用例

unittest.main(defaultTest="BusinessCase.test_01")

指定执行某些用例

cases =["BusinessCase.test_01", "BusinessCase.test_03"]
    unittest.main(defaultTest=cases)

defaultTest入参填写方式是类名.测试方法名.那有人就有疑问为什么是入参形式是类名.方法名呢?我们看下源码。第一个标红框的地方可以看到使用split方法按"."把字符串拆分成列表,也就是把"BusinessCase.test_01"转换成[“BusinessCase”,“test_01”]。第二个红框的地方调用getattr方法进行属性值判断。先是getattr(模块,类名),再是getattr(类名,方法名)。如果入参形式是错的,属性值不存在就报AttributeError异常,也是有代码下面也是写了这种异常如何处理。那么这条用例执行结果就是E(错误)。再给大家打印下这些值是啥。

在unittest框架中TextTestRunner表示________ unittest的方法_运行方式_03

在unittest框架中TextTestRunner表示________ unittest的方法_单元测试_04

我们defaultTest=BusinessCase.test_04。传入不存在测试方法,看下运行结果:

cases =["BusinessCase.test_01", "BusinessCase.test_04", "BusinessCase.test_03"]
    unittest.main(defaultTest=cases)

运行结果如下图。先看test_04测试方法的执行结果是E,表示错误。再看错误信息,失败的测试用例,再下面是属性错误,BusinessCse没有test_04属性。写到这里大家应该明白了defaultTest入参为啥要这么写了吧。大家可能还迷惑getattr方法怎么使用。那我们再把getattr方法学习下,我也是巩固下。

在unittest框架中TextTestRunner表示________ unittest的方法_python_05

新建jx_02_getattr.py文件,文件内容如下:

class Demo(object):

    def test_01(self):
        print("测试方法1")

    def test_02(self):
        print("测试方法2")

我们调用getattr方法,看下jx_02_getattr.py有没有Demo属性,Demo中是否有test_01属性。

if __name__ == "__main__":
    mouble =__import__("__main__")
    print(getattr(mouble,"Demo"))
    print(getattr(Demo,"test_01"))

运行结果如下图,jx_02_getattr.py有Demo属性,Demo中有test_01属性,那么直接返回其属性值

在unittest框架中TextTestRunner表示________ unittest的方法_运行方式_06

我们再调用getattr方法,看下Demo中是否有test_03属性

if __name__ == "__main__":
    print(getattr(Demo,"test_03"))

运行结果如下图,Demo中没有test_03属性,报没有属性的异常,跟上面的异常一样。到这里大家应该明白了吧。

在unittest框架中TextTestRunner表示________ unittest的方法_测试方法_07

第三种运行方式。使用测试套件类,类对象调用addtest/addtests方法,添加测试用例。后面几种方法都用到了测试套件。

if __name__ == "__main__":
    # cases =["BusinessCase.test_01", "BusinessCase.test_04", "BusinessCase.test_03"]

    suite = unittest.TestSuite()
    suite.addTest(BusinessCase("test_01"))
    unittest.main(defaultTest="suite")

那我们来看下TestSuite类,点进去TestSuite类中没有addTest方法,然后去他的父类BaseTestSuite看下,在BaseTestSuite类中找到了addTest和addTests方法。

在unittest框架中TextTestRunner表示________ unittest的方法_单元测试_08

在unittest框架中TextTestRunner表示________ unittest的方法_运行方式_09

那我们在再研究下addtest方法传参形式为啥是类名(方法名),看下第二个图的46行,使用了callable方法判断传入test是否能被调用,也就是BusinessCase(“test_01”)是否能被调用。callable方法我们简单举例看下吧。
新建jx_03_callable.py文件,内容如下:

import unittest

class Demo(unittest.TestCase):

    def test_01(self):
        print("测试方法1")

    def test_02(self):
        print("测试方法2")

if __name__ == "__main__":
    test =Demo("test_01")
    print(callable(test))

我们调用callable方法查看Demo类中test_01方法能否的被调用,结果返回True。

在unittest框架中TextTestRunner表示________ unittest的方法_单元测试_10


我们再调用callable方法查看Demo类中test_03方法能否的被调用,结果抛出异常。

在unittest框架中TextTestRunner表示________ unittest的方法_单元测试_11


到这里大家应该明白addTest方法了吧。

那是不是又好奇,defaultTest=”suite“ 为什么要这样传值,不应该是类名.方法名吗?我也不知道为啥,我还好奇为啥不是defaultTest=suite。我们再打印一些参数方便我们理解下。

我们先打印suite现在是什么值

<unittest.suite.TestSuite tests=[<__main__.BusinessCase testMethod=test_01>]>

defaultTest=”suite“ ,那么就走红框的逻辑,变成了元组,self.testNames=(“suite”,)

在unittest框架中TextTestRunner表示________ unittest的方法_测试用例_12


再走这里

在unittest框架中TextTestRunner表示________ unittest的方法_单元测试_13


选第一个

在unittest框架中TextTestRunner表示________ unittest的方法_python_14


再走到这里,是不是很熟悉,我们方法二已经看过一次了。我们做下打印。发现getattr(模块名,类名)没有问题。到这里大家应该明白defaultTest=”suite“ 这样传值的原因了吧。

在unittest框架中TextTestRunner表示________ unittest的方法_运行方式_15


在unittest框架中TextTestRunner表示________ unittest的方法_测试用例_16

第四个运行方式。加载器的使用,执行指定目录下的指定.py文件。这样就是全部用例执行。start_dir是当前文件目录,pattern传入需要执行的文件,它可以多文件执行。比如pattern=“*.py”,就是执行当前目录下的所有.py文件。我们点开discover方法,看见pattern有默认值,那我们写测试用例文件名时,最好就是以test开头。

suite = unittest.TestSuite()
    cases = unittest.defaultTestLoader.discover(start_dir=os.getcwd(),pattern="jx_01_case.py")
    print(cases)
    suite.addTests(cases)
    unittest.main(defaultTest="suite")

在unittest框架中TextTestRunner表示________ unittest的方法_python_17


第五个运行方式。这里是用了makeSuite方法,传的是测试类。也是全部用例执行。

suite = unittest.TestSuite()
    cases = unittest.makeSuite(BusinessCase)
    suite.addTests(cases)
    unittest.main(defaultTest="suite")

在unittest框架中TextTestRunner表示________ unittest的方法_单元测试_18

第六种运行方式,使用TextTestRunner测试运行器

suite = unittest.TestSuite()
    cases = unittest.defaultTestLoader.discover(start_dir=os.getcwd(),pattern="jx_01_case.py")
    print(cases)
    suite.addTests(cases)
    unittest.TextTestRunner().run(suite)

其实unittest.main()也是使用的TextTestRunner().run()方法。

好啦,六种方式整理完了,可能还有其他运行方式,这里我也不多列举了。喜欢的点个赞,有钱的再打赏。