Py文档和测试及应用(pydoc、doctest、unittest)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44015805/article/details/100936272
# -*- coding: utf-8 -*-
'''
#Py文档和测试.py
(pydoc、doctest、unittest)


注意:
1、pydoc 查看文档
python3 -m pydoc -b
在任意一个未占用的端口启动HTTP服务器,接下来用户同样可以通过浏览器来查看 Python 的所有模块的文档信息。
2、unittest 要求单元测试类必须继承 unittest.TestCase,该类中的测试方法需要满足如下要求:
测试方法应该没有返回值。
测试方法不应该有任何参数。
测试方法应以test 开头。


使用:
一、pydoc  在控制台中查看文档
1、python -m pydoc 模块名
pydoc 模块在控制台中查看帮助文档的命令
命令中的 -m 是 python 命令的一个选项,表示运行指定模块,此处表示运行 pydoc 模块。后面的“模块名”参数代表程序要查看的模块。
按下空格键,pydoc 将会使用第二屏来显示文档信息
2、python -m pydoc -w 模块名
pydoc 模块额外指定了 -w 选项,该选项代表 write,表明输出 HTML 文档。
可以在该目录下发现额外生成了一个 fkmodule.html 文件,使用浏览器打开该文件
3、python3 -m pydoc -p 端口号
在指定端口启动 HTTP 服务器,接下来用户可以通过浏览器来查看 Python 的所有模块的文档信息
4、python3 -m pydoc -b
在任意一个未占用的端口启动HTTP服务器,接下来用户同样可以通过浏览器来查看 Python 的所有模块的文档信息。

二、doctest 文档测试模块  
doctest 模块运行 Python 源文件的说明文档中的测试用例,从而生成测试报告。
文档测试工具可以提取说明文档中的测试用例,其中“>>>”之后的内容表示测试用例,接下来的一行则代表该测试用例的输出结果。
文档测试工具会判断测试用例的运行结果与输出结果是否一致,如果不一致就会显示错误信息。

三、unittest 单元测试模块
PyUnit(unittest) 是 Python 自带的单元测试框架,用于编写和运行可重复的测试。
PyUnit 是 xUnit 体系的一个成员,xUnit 是众多测试框架的总称,PyUnit 主要用于进行白盒测试和回归测试。

1、unittest.TestCase单元测试用例类
测试用例类:测试用例类就是单个的测试单元,其负责检查特定输入和对应的输出是否匹配。unittest 提供了一个 TestCase 基类用于创建测试用例类。
unittest 要求单元测试类必须继承 unittest.TestCase,该类中的测试方法需要满足如下要求:
测试方法应该没有返回值。
测试方法不应该有任何参数。
测试方法应以test 开头。
1.1、unittest 运行方式有两种:
一种是调用 unittest.main() 来运行当前源文件中的所有测试用例。程序代码最后调用主函数__main__
另一种是命令行输入:  python -m unittest 单元测试用例文件
1.2、unittest.TestCase类中 内置了大量 assertXxx 方法来执行断言

2、unittest.TestSuite测试包类
测试包:用于组合多个测试用例,测试包也可以嵌套测试包。
3、unittest.TextTestRunner测试运行器类
测试运行器:负责组织、运行测试用例,并向用户呈现测试结果。

4、unittest.TestCase测试用例类的 测试固件方法
unittest.TestCase 包含了 setUp() 和 tearDown() 两个方法,
其中 setUp() 方法用于初始化测试固件;而 tearDown() 方法用于销毁测试固件。

5、unittest跳过测试用例
5.1、使用 skipXxx 装饰器来跳过测试用例。
5.2、使用TestCase 的 skipTest() 方法来跳过测试用例。

'''



# =============================================================================
# doctest模块  
# doctest 模块运行 Python 源文件的说明文档中的测试用例,从而生成测试报告。
# 文档测试工具可以提取说明文档中的测试用例,其中“>>>”之后的内容表示测试用例,接下来的一行则代表该测试用例的输出结果。
# 文档测试工具会判断测试用例的运行结果与输出结果是否一致,如果不一致就会显示错误信息。
# =============================================================================

#测试输出结果很清晰,每个测试用例结果都包含如下 4 部分:
#1、第一部分:  显示在哪个源文件的哪一行。
#2、第二部分:  Failed example,显示是哪个测试用例出错了。
#3、第三部分:  Expected,显示程序期望的输出结果。也就是在“>>>命令”的下一行给出的运行结果,它就是期望结果。
#4、第四部分:  Got,显示程序实际运行产生的输出结果。只有当实际运行产生的输出结果与期望结果一致时,才表明该测试用例通过。

def square (x):
    '''
    一个用于计算平方的函数
    例如
    >>> square(2)
    4
    >>> square(3)
    9
    >>> square(-3)
    9
    >>> square(0)
    0
    '''
    return x * 2 # ①、故意写错的
class User:
    '''
    定义一个代表用户的类,该类包含如下两个属性:
    name - 代表用户的名字
    age - 代表用户的年龄
    例如
    >>> u = User('fkjava', 9)
    >>> u.name
    'fkjava'
    >>> u.age
    9
    >>> u.say('i love python')
    'fkjava说: i love python'
    '''
    def __init__(self, name, age):
        self.name = 'fkit' # ②、故意写错的
        self.age = age
    def say(self, content):
        return self.name + '说: ' + content
if __name__=='__main__':
    import doctest
    doctest.testmod()







# =============================================================================
# unittest单元测试模块
# PyUnit(unittest) 是 Python 自带的单元测试框架,用于编写和运行可重复的测试。
# PyUnit 是 xUnit 体系的一个成员,xUnit 是众多测试框架的总称,PyUnit 主要用于进行白盒测试和回归测试。
# =============================================================================

#PyUnit 是一个简单、易用的测试框架,其具有如下特征:
#1、使用断言方法判断期望值和实际值的差异,返回 bool 值。
#2、测试驱动设备可使用共同的初始化变量或实例。
#3、测试包结构便于组织和集成运行。


#注意:
#PyUnit 测试与其他 xUnit 的套路一样,基于断言机制来判断函数或方法的实际输出结果和期望输出结果是否一致,
#测试用例提供参数来执行函数或方法,获取它们的执行结果,
#然后使用断言方法来判断该函数或方法的输出结果与期望输出结果是否一致,
#如果一致则说明测试通过;如果不一致则说明测试不通过。



#示例   
#新建一个简单的程序,用于后期编写测试代码测试
#该程序包含两个函数,分别用于计算 一元一次方程的解 和 二元一次方程的解。
#testUnittest_main.py
    
def one_equation(a , b):
    '''
    求一元一次方程a * x + b = 0的解
    参数a - 方程中变量的系数
    参数b - 方程中的常量
    返回 方程的解
    '''
    if a == 0:
        raise ValueError("参数错误")                  # 如果a = 0,则方程无法求解
    else:
        return -b / a  # ①
#        return b / a                                 # 返回方程的解 
    
def two_equation(a , b , c):
    '''
    求一元二次方程a * x * x + b * x + c = 0的解
    参数a - 方程中变量二次幂的系数
    参数b - 方程中变量的系数
    参数c - 方程中的常量
    返回 方程的根
    '''
    if a == 0:
        raise ValueError("参数错误")                 # 如果a == 0,变成一元一次方程
    elif b * b - 4 * a * c < 0:
        raise ValueError("方程在有理数范围内无解")    # 有理数范围内无解
    elif b * b - 4 * a * c == 0:                    # 方程有唯一的解
        return -b / (2 * a)                         # 使用数组返回方程的解
    else:                                           # 方程有两个解
        r1 = (-b + (b * b - 4 * a * c) ** 0.5) / 2 / a
        r2 = (-b - (b * b - 4 * a * c) ** 0.5) / 2 / a
        return r1, r2                              # 方程的两个解

#定义好上面的 testUnittest_main.py 程序之后,该程序就相当于一个模块,
#接下来为该模块编写单元测试代码。


####################
#unittest.TestCase单元测试用例类
#测试用例类:测试用例类就是单个的测试单元,其负责检查特定输入和对应的输出是否匹配。unittest 提供了一个 TestCase 基类用于创建测试用例类。
#unittest 要求单元测试用例类必须继承 unittest.TestCase,该类中的测试方法需要满足如下要求:
#1、测试方法应该没有返回值。
#2、测试方法不应该有任何参数。
#3、测试方法应以test 开头。


#示例:    以下为单元测试用例文件代码
#测试用例中使用断言方法判断函数的实际输出结果与期望输出结果是否一致,如果一致则表明测试通过,否则表明测试失败。
#testUnittest_test_main.py
import unittest
from testUnittest_main import *

class TestFkMath(unittest.TestCase):

    def test_one_equation(self):
        '''测试一元一次方程的求解'''
        self.assertEqual(one_equation(5 , 9) , -1.8)              #断言该方程求解应该为-1.8
        self.assertTrue(one_equation(4 , 10) == -2.5 , .00001)    #断言该方程求解应该为-2.5
        self.assertTrue(one_equation(4 , -27) == 27 / 4)          #断言该方程求解应该为27/4
        with self.assertRaises(ValueError):                       #断言当a == 0时的情况,断言引发ValueError
            one_equation(0 , 9)

    def test_two_equation(self):
        '''测试一元二次方程的求解'''
        r1, r2 = two_equation(1 , -3 , 2)
        self.assertCountEqual((r1, r2), (1.0, 2.0), '求解出错')
        
        r1, r2 = two_equation(2 , -7 , 6)
        self.assertCountEqual((r1, r2), (1.5, 2.0), '求解出错')

        r = two_equation(1 , -4 , 4)                              #断言只有一个解的情形
        self.assertEqual(r, 2.0, '求解出错')

        with self.assertRaises(ValueError):                       #断言当a == 0时的情况,断言引发ValueError
            two_equation(0, 9, 3)

        with self.assertRaises(ValueError):                       #断言引发ValueError
            two_equation(4, 2, 3)

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


#使用:

#编写完测试用例之后,可以使用如下两种方式来运行它们:

#1、通过代码调用测试用例。程序可以通过调用 unittest.main() 来运行当前源文件中的所有测试用例。例如,在上面的测试用例中增加如下代码:
#if __name__ == '__main__':
#    unittest.main()
    
#2、使用 unittest 模块运行单元测试用例文件。使用该模块的语法格式如下:
#python -m unittest 单元测试用例文件
#在使用 python -m unittest 命令运行测试用例时,如果没有指定测试用例,该命令将自动查找并运行当前目录下的所有测试用例。因此,程序也可直接使用如下命令来运行所有测试用例:
#py -m unittest




#使用:
#unittest.TestCase类中 内置了大量 assertXxx 方法来执行断言
import unittest

help(unittest.TestCase)
dir(unittest.TestCase)

help(unittest.TestCase.assertEqual)                                #断言检查参数a==参数b
#...

#TestCase 中最常用的断言方法
#断言方法                  	检查条件
#assertEqual(a, b)        	a == b
#assertNotEqual(a, b)    	a != b
#assertTrue(x)	            bool(x) is True
#assertFalse(x)	            bool(x) is False
#assertIs(a, b)	            a is b
#assertIsNot(a, b)        	a is not b
#assertIsNone(x)           	x is None
#assertIsNotNone(x)        	x is not None
#assertIn(a, b)	            a in b
#assertNotIn(a, b)	        a not in b
#assertlsInstance(a, b)	    isinstance(a, b)
#assertNotIsInstance(a, b)	not isinstance(a, b)
    

#异常、错误、警告和日志相关的断言方法
#断言方法	                                       检查条件
#assertRaises(exc, fun, *args, **kwds)	           fun(*args, **kwds) 引发 exc 异常
#assertRaisesRegex(exc, r, fun, *args, **kwds)	   fun(*args, **kwds) 引发 exc 异常,且异常信息匹配 r 正则表达式
#assertWarns(warn, fun, *args, **kwds)	           fun(*args, **kwds) 引发 warn 警告
#assertWamsRegex(warn, r, fun, *args, **kwds)	   fun(*args, **kwds) 引发 warn 警告,且警告信息匹配 r 正则表达式
#assertLogs(logger, level)                         With 语句块使用日志器生成 level 级别的日志


#完成某种特定检查的断言方法
#断言方法	                                        检查条件
#assertAlmostEqual(a, b)	                        round(a-b, 7) == 0
#assertNotAlmostEqual(a, b)                     	round(a-b, 7) != 0
#assertGreater(a, b)	                            a > b
#assertGreaterEqual(a, b)                        	a >= b
#assertLess(a, b)	                                a < b
#assertLessEqual(a, b)	                            a <= b
#assertRegex(s, r)	                                r.search(s)
#assertNotRegex(s, r)	                            not r.search(s)
#assertCountEqual(a, b)	                            a、b 两个序列包含的元素相同,不管元素出现的顺序如何






####################
#unittest.TestSuite测试包类
#测试包:用于组合多个测试用例,测试包也可以嵌套测试包。
#及
#unittest.TextTestRunner测试运行器类
#测试运行器:负责组织、运行测试用例,并向用户呈现测试结果。


#示例
#为了示范测试包的功能,下面再开发一个程序(testUnittest_hello.py):
#testUnittest_hello.py
def say_hello():
    #该方法简单地返回字符串
    return "Hello World."
def add(nA, nB):
    #计算两个整数的和
    return nA + nB
    
#接下来为上面程序提供如下测试类(testUnittest_test_hello.py):
#testUnitest_test_hello.py
import unittest
from testUnittest_hello import *

class TestHello(unittest.TestCase):
    def test_say_hello(self):
        #测试say_hello函数
        self.assertEqual(say_hello() , "Hello World.")
    def test_add(self):
        #测试add函数
        self.assertEqual(add(3, 4) , 7)
        self.assertEqual(add(0, 4) , 4)
        self.assertEqual(add(-3, 0) , -3)

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

#示例  unittest.TestSuite测试包类 及 unittest.TextTestRunner测试运行器类
#将 testUnittest_test_math.py 和 testUnittest_test_hello.py 文件放在同一目录,
#此时程序就可以通过 TestSuite 将它们组织在一起,
#然后使用 TestRunner 来运行该测试包。
import unittest
from testUnittest_test_math import TestFkMath
from testUnittest_test_hello import TestHello

test_cases=(TestHello, TestFkMath)                           #将 多个测试用例 组成一个元祖

def whole_suite():
    loader=unittest.TestLoader()                             #创建测试加载器
    #创建测试包  用于组合多个测试用例,测试包也可以嵌套测试包。
    suite=unittest.TestSuite()
    for test_class in test_cases:                            #遍历所有测试类
        tests=loader.loadTestsFromTestCase(test_class)       #从测试类中加载测试用例
        #将测试用例添加到测试包中
        suite.addTests(tests)
    return suite   

if __name__ == '__main__':
    runner=unittest.TextTestRunner(verbosity=2)              #创建测试运行器(TestRunner)
    runner.run(whole_suite())

#if __name__ == '__main__':
#    with open('testUnittest_test_report.txt', 'a') as f:
#        # 创建测试运行器(TestRunner),将测试报告输出到文件中
#        runner = unittest.TextTestRunner(verbosity=2, stream=f)
#        runner.run(whole_suite())




####################
#unittest.TestCase测试用例类的 测试固件方法
#unittest.TestCase 包含了 setUp() 和 tearDown() 两个方法,
#其中 setUp() 方法用于初始化测试固件;而 tearDown() 方法用于销毁测试固件。


#程序会在运行每个测试用例(以 test_ 开头的方法)之前自动执行 setUp() 方法来初始化测试固件,
#井在每个测试用例(以 test_ 开头的方法)运行完成之后自动执行 tearDown() 方法来销毁测试固件。
#如果希望程序为测试用例初始化、销毁测试固件,那么只要重写 TestCase 的 setUp() 和 tearDown() 方法即可

#示例  重写测试用例的测试固件方法
#testUnittest_fixture.py
import unittest
from testUnittest_hello import *

class TestHello(unittest.TestCase):

    def test_say_hello(self):    
        #测试say_hello函数
        self.assertEqual(say_hello() , "Hello World.")
    def test_add(self):    
        #测试add函数
        self.assertEqual(add(3, 4) , 7)
        self.assertEqual(add(0, 4) , 4)
        self.assertEqual(add(-3, 0) , -3)

#    #如果希望程序在该类的所有测试用例执行之前都用一个方法来初始化测试固件,在该类的所有测试用例执行之后都用一个方法来销毁测试固件,
#    #则可通过重写 setUpClass() 和 tearDownClass() 类方法来实现。
#    @classmethod
#    def setUpClass(cls):
#        print('\n====执行setUpClass在类级别模拟初始化固件====')
#    @classmethod
#    def tearDownClass(cls):
#        print('\n====调用tearDownClass在类级别模拟销毁固件====')
        
    def setUp(self):
        print('\n====执行setUp模拟初始化固件====')
        
    def tearDown(self):
        print('\n====调用tearDown模拟销毁固件====')
        
#使用如下命令来运行该测试程序:
#python -m unittest -v fixture_test.py




####################
#unittest跳过测试用例
#使用 skipXxx 装饰器来跳过测试用例。
#使用TestCase 的 skipTest() 方法来跳过测试用例。
        

#如果希望临时跳过某个测试用例,则可以通过如下两种方式来实现:
        
#1、使用 skipXxx 装饰器来跳过测试用例。
#unittest 一共提供了 3 个装饰器,分别是 @unittest.skip(reason)、@unittest.skipIf(condition, reason) 和 @unittest.skipUnless(condition, reason)。
#其中 skip 代表无条件跳过,skipIf 代表当 condition 为 True 时跳过;skipUnless 代表当 condition 为 False 时跳过。

#2、使用TestCase 的 skipTest() 方法来跳过测试用例。


#示例  使用 @unittest.skip 装饰器来跳过测试用例
#testUnittest_skip_testA.py
import unittest
from testUnittest_hello import *

class TestHello(unittest.TestCase):
    # 测试say_hello函数
    def test_say_hello(self):
        self.assertEqual(say_hello() , "Hello World.")
    # 测试add函数
    @unittest.skip('临时跳过test_add')
    def test_add(self):
        self.assertEqual(add(3, 4) , 7)
        self.assertEqual(add(0, 4) , 4)
        self.assertEqual(add(-3, 0) , -3)

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


#示例  使用 TestCase 的 skipTest() 方法跳过测试用例
#testUnittest_skip_testB.py
import unittest
from testUnittest_hello import *

class TestHello(unittest.TestCase):
    # 测试say_hello函数
    def test_say_hello(self):
        self.assertEqual(say_hello() , "Hello World.")
    # 测试add函数
    def test_add(self):
        self.skipTest('临时跳过test_add')
        self.assertEqual(add(3, 4) , 7)
        self.assertEqual(add(0, 4) , 4)
        self.assertEqual(add(-3, 0) , -3)
if __name__=="__main__":
    unittest.main()
















猜你喜欢

转载自blog.csdn.net/weixin_44015805/article/details/100936272