疯狂Python讲义学习笔记(含习题)之文档和测试


软件测试的目的是为了找出软件系统中存在的缺陷,然后将这些缺陷提交给Bug管理系统(如Bugzilla等)。

一、使用pydoc生成文档

借助于Python自带的pydoc模块,可以非常方便地查看、生成帮助文档,该文档是HTML格式的,因此查看、使用起来都非常方便。

MY_NAME = '冰蓝工作室'


def say_hi(name):
    '''
    定义一个打招呼的函数
    返回对指定用户打招呼的字符串
    '''
    print("执行say_hi函数")
    return name + '您好!'


def print_rect(height, width):
    '''
    定义一个打印矩形的函数
    :param heiht: 代表矩形的高
    :param width: 代表矩形的宽
    '''
    print(('*' * width + '\n') * height)


class User:
    NATIONAL = 'China'
    '''
    定义一个代表用户的类
    该类包括name、age两个变量
    '''

    def __init__(self, name, age):
        '''
        name初始化该用户的name
        age初始化该用户的age
        '''
        self.name = name
        self.age = age

    def eat(food):
        '''
        定义用户吃东西方法。
        food——代表正在吃的东西
        '''
        print('{0}正在吃{1}'.format(self.name, food))

(一)在控制台中查看文档

使用pydoc模块在控制台中查看帮助文档的命令如下:
python -m pydoc 模块名
其中-m是python命令的一个选项,表示运行指定模块,此处表示运行pydoc模块。
在代码目录下运行命令 python -m pydoc ibmodule得到如下图输出结果:

在这里插入图片描述
pydoc文档总是按如下顺序来显示模块中的全部内容

  • 模块的文档说明:就是*.py文件顶部的注释信息,这部分信息会被提取成模块的文档说明。也就是上图中①的部分
  • CLASS部分:这部分会列出该模块所包含的全部类。也就是上图中②的部分
  • FUNCTIONS部分:这部分会列出该模块所包含的全部函数。也就是上图中③的部分
  • DATA部分:这部分会列出该模块所包含的全部成员变量。也就是上图中④的部分
  • FILE部分:这部分会显示该模块对应的源文件位置。也就是上图中⑤的部分

(二)生成HTML文档

使用pydoc模块生成HTML帮助文档的命令如下:
python -m pydoc -w 模块名
以上命令中额外指定了-w选项,该选项代表write,表明输出HTML文档。
在这里插入图片描述
可以看到,在模块所在目录下生成了一个ibmodule.html文件,该文件更加清晰的描述了模块的帮助信息。
在这里插入图片描述
pydoc还可用于为指定目录生成HTML文档。如:python -m pydoc -w 目录名

(三)启动本地服务器来查看文档信息

python -m pydoc -p 端口号
以上命令在指定端口启动HTTP服务器,接下来用户可以通过浏览器来查看python的所有模块的文档信息。

(四)查找模块

pydoc还提供了一个-k选项,该选项用于查找模块。
python -m pydoc -k 被搜索模块的部分内容

二、软件测试概述

软件测试是保证软件质量的重要手段之一。

(一)软件测试的概念和目的

IEEE定义:测试是使用人工和自动手段来运行或检测某个系统的过程,其目的在于检验系统是否满足规定的需求,或者弄清预期结果与实际结果之间的差别。
软件测试基本原则:

  • 应该尽早并不断地进行软件测试。
  • 测试用例应该由测试输入数据和对应的预期输出结果两部分组成
  • 开发人员避免测试自己的程序
  • 在设计测试用例时,至少应该包括合理的输入和不合理的输入两种
  • 应该充分注意测试中的群集现象,经验表明,测试后程序中残存的错误数目与该程序中已发现的错误数呈正比
  • 严格执行测试计划,避免测试的随意性
  • 应当对每一个测试结果都做全面检查
  • 妥善保存测试计划、测试用例、出错统计和最终分析报告,为维护提供方便

(二)软件测试的分类

从软件工程的总体把握来分,软件测试可以分为:

  • 静态测试:针对测试不运行部分进行检查和审阅。静态测试又分为三类:
    • 代码审阅:检查代码涉及的一致性,检查代码的标志性、可读性,包括代码结构的合理性。
    • 代码分析:主要针对程序进行流程分析,包括数据流分析、接口分析和表达式分析等。
    • 文档检查:主要检查各阶段的文档是否完备。
  • 动态测试:通过运行和试探发现缺陷。动态测试又分为两类:
    • 结构测试(白盒):各种覆盖测试。
    • 功能测试(黑盒):集成测试、系统测试和用户测试等。

从软件测试工程的大小来分,软件测试又可分为如下类别:

  • 单元测试:测试中的最小单位,测试特殊的功能和代码模块。通常由开发者完成。
  • 集成测试:测试应用程序结合的部分来确定他们的功能是否正确,主要测试功能模块或独立的应用程序。
  • 系统测试:典型的黑盒测试,与应用程序的功能需求紧密相关。
  • 用户测试:分为α和β测试,α测试由测试人员模拟最终用户来完成。β测试由最终用户来完成,在实际使用环境中试用。
  • 平行测试:同时运行新开发的系统和即将取代的旧系统,比较新旧两个系统的运行结果。

(三)开发活动和测试活动

软件开发常规流程:

  1. 软件开发人员发布一个新功能、新模块,随之一起提交的还有软件开发文档、发布文档(包括新增了哪些功能、改进了哪些功能),以及软件安装、部署等相关文档。
  2. 软件测试人员按照软件开发人员提供的文档来安装、部署新功能、新模块。
  3. 软件测试人员准备进行测试,在测试之前要编写详细的测试计划并准备测试用例。
  4. 软件测试人员进行实际测试,并编写一些自动化测试脚本,以简化下一次的回归测试,然后将测试发现的Bug提交到Bug管理系统(如Bugzilla) 。
  5. 软件开发人员查看Bug管理系统,对软件测试人员提交的Bug进行修复,提交所做的修改,并在Bug管理系统中将该Bug设为己修复。
  6. 软件测试人员针对己修复的Bug进行回归测试。如果Bug依然存在,则在Bug管理系统中将Bug重新打开(即将其设为需要修复的Bug) 。
  7. 重复5、6两个步骤,知道测试没有发现Bug为止。

(四)常见的Bug管理工具

主流Bug管理工具:

  • Bugzilla:一个开源、免费且功能强大的Bug管理工具,只有在初次使用时其配置、上手稍微复杂一点。可以与CVS进行整合开发。
  • BugFree:一个开源、免费的Bug管理工具,它是一款B/S结构的Bug管理软件。
  • TestDirector:由Mercury Interactive 公司(著名的软件测试工具提供商,现己被惠普收购)开发的一款商业的软件测试管理工具,也是业界第一个基于Web 的测试管理系统,从而允许软件开发和软件测试人员既可在公司内部,也可在公司外部进行测试管理。
  • JIRA:由Atlassian公司提供的一款集项目计划、任务分配、需求管理、Bug跟踪于一体的商业软件。
  • ClearQuest:IBM 的Rational 旗下的一个专业的Bug 管理工具,它可以对Bug 和记录的变化进行跟踪管理,也可以跟踪一个Bug 完整的生命周期,从提交到关闭, ClearQuest 可以记录Bug 所有的改变历史。同时ClearQuest 提供了各种方便的查询功能,从而可以及时了解每个Bug 的处理情况。
  • MantisBT:一个基于PHP + MySQL (或SQL Server 、PostgreSQL )技术开发的B/S 结构的Bug 管理系统,开源、免费。

三、文档测试

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

def square(x):
    '''
    一个用于计算平方的函数
    :param x: 待计算的数
    :return: 计算结果
    例如:
    >>> square(2)
    4
    >>> square(3)
    9
    >>> square(-3)
    9
    >>> square(0)
    0
    '''
    return x * 2 # 故意写错


class User:
    '''
    定义一个代表用户的类,该类包含如下两个属性
    name:代表用户的名字
    age:代表用户的年龄

    例如:
    >>> u = User('ib-top', 9)
    >>> u.name
    'ib-top'
    >>> u.age
    9
    >>> u.say('i love python')
    'ib-top说:i love python'
    '''

    def __init__(self, name, age):
        self.name = 'ib_top' # 故意写错
        self.age = age

    def say(self, content):
        return self.name + '说:' + content


if __name__ == '__main__':
    import doctest
    doctest.testmod()

运行结果:
在这里插入图片描述
每个测试用例结果都包含如下4个部分:

  • 第一部分:显示在哪个源文件的哪一行
  • 第二部分:Failed example,显示是哪个测试用例出错了
  • 第三部分:Expected,显示程序期望的输出结果
  • 第四部分:Got,显示程序实际运行产生的输出结果

四、单元测试

(一)单元测试概述

单元测试是一种小粒度的测试,用以测试某个功能或代码块。
好处:

  • 提高开发速度:借助专业框架,能以自动化方式执行,从而提高开发者开发、测试的执行效率。
  • 提高软件代码质量:使用小版本发布、集成,有利于开发人员实时除错,同时引入重构,使代码具有可扩展性。
  • 提升系统的可信赖度:作为一种回归测试,支持在修复或更正后进行“再测试”,保证代码的正确性。

被测对象:

  • 结构化编程语言中的函数
  • 面向对象编程语言中的接口、类、对象

任务:

  • 被测单元的接口测试
  • 被测单元的局部数据结构测试
  • 被测单元的边界条件测试
  • 被测单元中的所有独立执行路径测试
  • 被测单元中的各条错误处理路径测试

被测单元的接口测试指的是它与其他程序单元的通信接口,如调用方法的方法名、形参等。
接口测试是单元测试的基础,只有在数据能正确输入、输出的前提下,其他测试才有意义。
接口测试考虑因素:

  • 输入的实参与形参的个数、类型是否匹配
  • 调用其他程序单元(如方法)时所传入实参的个数、类型与被调用程序单元的形参的个数、类型是否匹配
  • 是否存在与当前入口点无关的参数引用
  • 是否修改了只读型参数
  • 是否把某些约束也作为参数传入了

如果被测程序单元还包含来自外部的输入/输出,则还应考虑如下因素:

  • 打开的输入/输出流是否正确
  • 是否正常打开、关闭了输入/输出流
  • 格式说明与输入/输出语句是否匹配
  • 缓冲区大小与记录长度是否匹配
  • 文件在使用前是否已经打开
  • 是否处理了文件尾
  • 是否处理了输入/输出错误

局部变量往往是错误的根源,应仔细设计测试用例,确保能发现以下错误:

  • 不合适或不兼容的类型声明
  • 没有为局部变量指定初值
  • 局部变量的初值或默认值有错
  • 局部变量名出错(包括手误拼错或不正确的截断)
  • 出现上溢、下溢和地址异常

除此之外,如果被测程序单元还与程序中的全局变量耦合,那么在进行单元测试时还应该查清全局变量对被测单元的影响。
软件测试还应着重检查一下问题:

  • 输出的出错信息是否易于理解、调试
  • 记录的错误信息与实际遇到的错误是否相符
  • 异常处理是否合适
  • 错误信息中是否包含足够的出错定位信息

(二)单元测试的逻辑覆盖

单元测试用例设计最基本、最简单的方法就是边界值分析。指测试经验表明大量的错误都发生在输入/输出范围的边界条件上,而不是某个范围内部。
单元测试的逻辑覆盖包括:

  • 语句覆盖——每条语句都至少执行一次
  • 判定(边)覆盖——每条语句都执行,每个判定的所有可能结果都至少执行一次
  • 条件覆盖——每条语句都执行,判定表达式的每种可能都取得各种结果
  • 判定-条件覆盖——同时满足判定覆盖和条件覆盖,每个判定条件的各种可能组合都至少出现一次
  • 路径覆盖——程序的每条可能路径都至少执行一次

1. 语句覆盖

设计若干测试用例,执行被测程序,是的每条可执行语句都至少执行一次。语句覆盖是最弱的逻辑覆盖测试

def test(a, b, m):
    if a > 10 and b == 0:
        m = a + b
    if a == 20 or m > 15:
        m += 1

以上代码的执行流程如下:

对于以上代码,可设计如下测试用例:

  • 用例1:a=20; b=0; m=3,程序按路径ACE执行,该代码的4条语句均得到执行,从而实现语句覆盖
  • 用例2:a=20; b=1; m=3,程序按路径ABE执行,没有做到语句覆盖,m = a + b没有被执行。

2. 判定(边)覆盖

设计若干测试用例,执行被测程序,使得程序中每个判断的取真分支和取假分支都至少执行一次,即判断真假值均得到满足,因此又被称为分支覆盖。

测试用例 a,b,m取值 通过路径
用例1 20,0,3 ACE
用例2 10,0,3 ABD
用例3 12,0,3 ACD
用例4 20,1,1 ABE

3. 条件覆盖

设计若干测试用例,执行被测试程序,使得每个判断中每个条件的可能取值都至少满足一次。
前面代码中一共包含以下几种情况:
(1) a>10,取真值,记为T1
(2) a>10,取假值,即a <= 10,记为F1
(3) b0,取真值,记为T2
(4) b
0,取假值,即b != 0,记为F2
(5) a20,取真值,记为T3
(6) a
20,取假值,即a != 20,记为F3
(7) m>15,取真值,记为T4
(8)m>15,取假值,即m <= 15,记为F4

测试用例 a,b,m取值 通过路径 覆盖条件
用例1 20,0,1 ACE T1, T2, T3, T4
用例2 5,0,2 ABD F1,T2,F3,F4
用例3 20,1,5 ABE T1,F2,T3,F4

3 个测试用例覆盖了4 个条件的8种情况。进一步分析发现, 3个测试用例也把两个判断的4个分支B 、C 、D 和E都覆盖了。但满足条件覆盖的测试用例不一定满足判定覆盖。

4. 判定-条件覆盖

求设计足够多的测试用例,使得判断中每个条件所有可能的组合都至少出现一次,并且每个判断本身的判定结果也至少出现一次。

测试用例 a,b,m取值 通过路径 覆盖条件
用例1 20,0,3 ACE T1, T2, T3, T4
用例2 20,1,10 ABC T1,T2,T3,F4
用例3 10,0,20 ABE F1,T2,F3,T4
用例4 1,2,3 ABD F1,F2,F3,F4

5. 路径覆盖

设计足够多的测试用例,覆盖程序中所有可能的路径。

测试用例 a,b,m取值 通过路径
用例1 20,0,3 ACE
用例2 5,0,2 ABD
用例3 20,1,10 ABE
用例4 12,0,7 ACD

测试的目的不是要证明程序的正确性,而是要尽可能找出程序中的缺陷。没有完备的测试方法,也就没有完备的测试活动。

五、使用PyUnit(unittest)

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

  • 可以使测试代码与产品代码分离
  • 针对某一个类的测试代码只需要进行较少的改动,便可以应用于另一个类的测试。
  • 开放源代码,可以进行二次开发,方便扩展

特征:

  • 使用断言方法判断期望值和实际值的差异,返回bool值
  • 测试驱动设备可使用共同的初始化变量和实例
  • 测试包结构便于组织和集成运行

(一)PyUnit(unittest)的用法

测试的本质:通过给定参数来执行函数,然后判断函数的实际输出结果和期望输出结果是否一致。
PyUnit基于断言机制来判断函数或方法的实际输出结果和期望输出结果是否一致。
测试驱动开发方式强调先编写测试用例,然后再编写函数和方法。
实例:

def one_equation(a, b):
    '''
    求一元一次方程a * x + b = 0的解
    :param a: 方程中变量的系数
    :param b: 房中的常量
    :return: 方程的解
    '''
    # 如果a = 0,则方程无法求解
    if a == 0:
        raise ValueError("参数错误")
    # 返回方程的解
    else:
        return -b / a


def two_equation(a, b, c):
    '''
    求一元二次方程a * x * x + b * x + c = 0的解
    :param a: 方程中变量二次幂的系数
    :param b: 方程中变量的系数
    :param c: 方程中的常量
    :return: 方程的解
    '''
    # 如果 a == 0 ,则变成一元一次方程
    if a == 0:
        raise ValueError("参数错误")
    # 在有理数范围内无解
    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

定义好以上程序之后,该程序就相当于一个模块,接下来就可以为该模块编写单元测试代码了。
unittest要求单元测试类必须继承unittest.TestCase,该类中的测试方法满足如下要求:

  • 测试方法应该没有返回值
  • 测试方法不应该有任何参数
  • 测试方法应以test_开头

下面是测试用例的代码:

import unittest
from tb_math import *


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

    # 测试一元二次方程的解
    def test_twoequation(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, '求解出错')
        # 断言当 a == 0 时的情况,断言引发ValueError
        with self.assertRaises(ValueError):
            two_equation(0, 9, 3)
        # 断言引发ValueError
        with self.assertRaises(ValueError):
            two_equation(4, 2, 3)

以上代码中使用断言方法判断函数的实际输出结果与期望结果是否一致,如果一致则表明测试通过,否则表明测试失败。

在测试某个方法时,如果实际测试要求达到某种覆盖程度,那么在编写测试用例时必须传入多组参数来进行测试,使得测试能达到指定的逻辑覆盖。

** TestCast中常用的断言方法**

断言方法 检查条件
assertEqual(a, b) a == b
assertNotEqueal(a, b) a != b
assertTrue(x) bool(x) is True
asseretFalse(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
assertIsInstance(a, b) isinstance(a, b)
assertNotIsInstance(a, b) not instance(a, b)

** TestCase包含的与异常、错误、警告和日志相关的断言方法 **

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

** TestCase包含的用于完成某种特定检查的断言方法 **

断言方法 检查条件
assertAlmostEqual(a, b) round(a-b, 7) == 0
assertNotAlmostEqual(a, b) round(a-b, 7) !=0
assertGreater(a, b) a > b
assrtGreaterEqual(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两个序列包含的元素相同,不管元素出现的顺序如何

** TestCase包含的针对特定类型的断言方法**

断言方法 用于比较的类型
assertMultiLineEqual(a, b) 字符串(string)
assertSequenceEqual(a, b) 序列(sequence)
assertListEqual(a, b) 列表(list)
assertTupleEqual(a, b) 元组(tuple)
assertSetEqual(a, b) 集合(set或frozenset)
assertDictEqual(a, b) 字典(dict)

(二)运行测试

(1) 通过代码调用测试用例。程序可以通过调用unittest.main()来运行当前源文件中的所有测试用例。

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

(2) 使用unittest模块运行测试用例。

python -m unittest 测试文件

(三)使用测试包

使用测试包(TestSuite)可以组织多个测试用例,测试包还可以嵌套测试包。在使用测试包组织多个测试用例和测试包之后,程序可以使用测试运行期(TestRunner)来运行该测试包所包含的所有测试用例。
假设有一个hello.py程序

# 该方法简单地返回字符串
def say_hello():
    return "Hello World."


# 计算两个整数的和
def add(nA, nB):
    return nA + nB

接下来编写一个测试类

import unittest
from 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.assertEqual(add(3, 4), 7)
        self.assertEqual(add(0, 4), 4)
        self.assertEqual(add(-3, 0), -3)

然后就可以通过TestSuite将前面的测试一元二次方程的测试用例和这个测试用例组织到一起,然后使用TestRunner来运行测试包了。

import unittest
from testuni_test_math import TestIbModule
from test_hello import TestHello

test_case = (TestHello, TestIbModule)


def whole_suite():
    # 创建测试加载数据
    loader = unittest.TestLoader()
    # 创建测试包
    suite = unittest.TestSuite()
    # 遍历所有测试类
    for test_class in test_case:
        # 从测试类中加载测试用例
        tests = loader.loadTestsFromTestCase(test_class)
        # 将测试用例添加到测试包中
        suite.addTests(tests)
    return suite


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

(四)测试固件之setUp和tearDown

测试固件:代表执行一个或多个测试用例所需的准备工作,以及相关联的准备操作,准备工作可能包括穿件临时数据库、创建目录、开启服务器进程等。
unittest.TestCase包含了setUp()和tearDown()两个方法,其中setUp()方法用于初始化测试固件;而tearDown()用于销毁测试固件。程序会在运行每个测试用例(以test_开头的方法)之前自动执行setUp()方法来初始化测试固件,并在每个测试用例运行完成之后自动执行tearDwon()方法来销毁测试固件。

(五)跳过测试用例

(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()方法来跳过测试用例。

习题

  1. 定义一个包,该包包含两个模块,在每个模块下定义两个函数和一个类,程序为这个包及其所包含的其他程序单元编写文档说明,并为包生成HTML文档。
    ① 新建test_package文件夹
    ② 在该文件夹下创建test_module1.py、test_module2.py两个文件
    test_module1.py
# -*- encoding: utf-8 -*-
"""
# @Time : 2020/1/1 19:08
# @Author : 冰蓝工作室
# @File : test_module1.py
# @Contact : [email protected]
# @License : (C)Copyright 2019, www.ib-top.com
# @Desc : None
"""


class Test_Class1:
    '''
    一个用来测试文档编写的类
    该类包括name、age两个属性
    '''

    def __init__(self, name, age):
        '''
        :param name: 初始化测试类的name属性
        :param age: 初始化测试类的age属性
        '''
        self.name = name
        self.age = age

    def run(self):
        '''
        定义奔跑的方法
        '''
        print('{0}正在奔跑!'.format(self.name))


def test_function1():
    '''
    一个测试文档编写的函数
    该函数打印自己的名字
    '''
    print("正在执行test_module1中的函数test_function1")


def test_function2(name, age):
    '''
    另一个测试文档编写的函数
    :param name: 代表姓名
    :param age: 代表年龄
    :return: 返回对指定用户打招呼的字符串
    '''
    return name + "您好!您的年龄是" + age

testmodule2.py

# -*- encoding: utf-8 -*-
"""
# @Time : 2020/1/1 19:39
# @Author : 冰蓝工作室
# @File : test_module2.py
# @Contact : [email protected]
# @License : (C)Copyright 2019, www.ib-top.com
# @Desc : None
"""


class Test_class2:
    '''
    一个用来测试文档编写的类
    该类包含name,age两个属性
    '''

    def __init__(self, name, age):
        '''
        类的初始化方法
        :param name: 初始化name属性
        :param age: 初始化age属性
        '''
        self.name = name
        self.age = age

    def sayHi(self):
        '''
        定义说话的方法
        :return: 说话的字符串
        '''
        return self.name + "说:我的年龄是" + self.age + "岁!"


def test_function1():
    '''
    模块test_module2的文档编写测试函数
    该函数打印自己的函数名
    '''
    print("正在执行test_module2中的函数test_function1")


def test_function2():
    '''
    模块test_module2的文档编写测试函数
    :return: 该函数返回自己的函数名
    '''
    return "test_module2中函数test_function2"

③使用pydoc模块生成HTML文档
从命令行进入test_package目录的上级目录,使用命令 python -m pydoc -w test_package.test_module1为第一个模块生成HTML文档,使用命令python -m pydoc -w test_package.test_module2为第二个模块生成HTML文档,使用命令python -m pydoc -w test_package为包生成HTML文档。
命令执行完后的目录结构为:

test_package
test_package.html
test_package.test_module1.html
test_package.test_module2.html
  1. 定义三个函数和一个类,为这些函数和类提供文档测试,并运行文档测试。
def add(x, y):
    '''
    一个用于计算加法的函数
    :param x: 加数
    :param y: 被加数
    :return: 两个数的和
    例如:
    >>> add(1, 2)
    3
    >>> add(1.1, 2)
    3.1
    >>> add(-1, 1)
    0
    >>> add(0, 1)
    1
    '''
    return x + y


def cube(x):
    '''
    计算一个数的立方
    :param x: 待计算的数
    :return: 计算结果
    例如:
    >>> cube(3)
    27
    >>> cube(2)
    8
    >>> cube(-2)
    -8
    >>> cube(1.1)
    1.3310000000000004
    >>> cube(0)
    0
    '''
    return x**3


def sayHi():
    '''
    打印固定字符串
    例如:
    >>> sayHi()
    Hello World!
    '''
    print('Hello World!')


class Person:
    '''
    定义一个代表人的类,该类包含如下两个属性
    name: 代表姓名
    age: 代表年龄

    例如:
    >>> p = Person('ib-top', 20)
    >>> p.name
    'ib-top'
    >>> p.age
    20
    >>> p.say('i love python')
    'ib-top说:i love python'
    '''

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self, content):
        return self.name + '说:' + content


if __name__ == '__main__':
    import doctest
    doctest.testmod()

  1. 定义三个函数和一个类,为这些函数和类提供单元测试,并运行单元测试。
import unittest


def add(x, y):
    '''
    计算两个数的和
    :param x: 加数
    :param y: 被加数
    :return: 两个数的和
    '''
    return a + b


def square(x):
    '''
    计算一个数的平方
    :param x: 待计算平方的数
    :return: 计算结果
    '''
    return x**2


def say():
    '''
    打印字符串Hello World!
    '''
    print('Hello World!')


class Person:
    '''
    定义代表人的类,包含两个属性name和age
    '''

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sayHi(self):
        return self.name + '说:我今年' + self.age + '岁!'


# 测试用例
class TestSequenceFunctions(unittest.TestCase):
    # 测试加法函数
    def test_add(self):
        # 断言结果为3
        self.assertEqual(add(1, 2), 3)
        # 断言结果为-1
        self.assertTrue(add(-2, 1) == -1, .00001)
        # 断言结果为0
        self.assertTrue(add(0, 0) == 0)

    # 测试平方函数
    def test_square(self):
        # 断言结果为4
        self.assertEqual(square(2), 4)
        # 断言结果为1
        self.assertTrue(square(-1) == 1)
        # 断言结果为0
        self.assertEqual(square(0), 0)

    # 测试打印函数
    def test_say(self):
        # 断言结果为Hello World!
        self.assertEqual(say(), 'Hello World!')

    def setUp(self):
        self.man = Person('ib-top', 29)
        print('set up now')

    def test1(self):
        self.assertEqual(self.man.name, 'ib-top')

    def test2(self):
        self.assertEqual(self.man.age, 29)

    def test3(self):
        self.assertEqual(self.man.sayHi(), 'ib-top说:我今年29岁!')


if __name__ == '__main__':
    unittest.main()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章