《Python基础教程》学习笔记——测试基础

本文详细介绍了Python测试的基础,包括先测试后编码的TDD原则,准确的需求说明,测试四步曲,以及常用的测试工具如doctest和unittest。此外,还探讨了如何使用PyChecker和PyLint进行源代码检查,以及性能分析的重要性。测试不仅是确保代码质量的关键,也是应对程序变化和改进的重要手段。
摘要由CSDN通过智能技术生成

测试基础

先测试再编码

测试在先,编码在后。这也称为测试驱动的编程

准确的需求说明

需求说明,也就是描述程序必须满足何种需求的文档(或便条)。
功能需求,即程序必须提供哪些功能。

理念是先编写测试,再编写让测试通过的程序。
测试程序就是需求说明,可帮助确保程序开发过程紧扣这些需求。

简单的测试程序。

from area import rect_area
height = 3
width = 4
correct_answer = 12
answer = rect_area(height, width)
if answer == correct_answer:
	print('Test passed ')
else:
	print('Test failed ')

做好应对变化的准备

自动化测试不仅可在编写程序时提供极大的帮助,还有助于在修改代码时避免累积错误,这在程序规模很大时尤其重要。

代码覆盖率

覆盖率(coverage)是一个重要的测试概念。
运行测试时,很可能达不到运行所有代码的理想状态。
可使用覆盖率工具,它们测量测试期间实际运行的代码所占的比例。

要确保较高的 测试覆盖率,方法之一是秉承测试驱动开发的理念。
只要能确保先编写测试再编写函数,就能肯定每个函数都是经过测试的。

测试四步曲

测试驱动开发过程的各个阶段。

  • (1) 确定需要实现的新功能。可将其记录下来,再为之编写一个测试。
  • (2) 编写实现功能的框架代码,让程序能够运行(不存在语法错误之类的问题),但测试依然无法通过。
  • (3) 编写让测试刚好能够通过的代码。
  • (4) 改进(重构)代码以全面而准确地实现所需的功能,同时确保测试依然能够成功。

测试工具

  • unittest : 一个通用的测试框架。
  • doctest : 一个更简单的模块,是为检查文档而设计的,但也非常适合用来编写单元测试。

doctest

假设编写了一个计算平方的函数,并在其文档字符串中添加了一个示例。

def square(x):
	'''
	计算平方并返回结果
	>>> square(2)
	4
	>>> square(3)
	9
	'''
	return x * x

假设函数 square是在模块 my_math (即文件my_math.py)中定义的,就可在模块末尾添加如下代码:

if name =='__main__':
	import doctest, my_math
	doctest.testmod(my_math)

函数 doctest.testmod 读取模块中的所有文档字符串,查找看起来像是从交互式解释器中摘取的示例,再检查这些示例是否反映了实际情况。

为获得更多的输出,可在运行脚本时指定开关 -v (verbose,意为详尽)。

$ python my_math.py -v

生成如下输出:

Running my_math.__doc__
0 of 0 examples failed in my_math.__doc__
Running my_math.square.__doc__
Trying: square(2)
Expecting: 4
Ok

Trying: square(3)
Expecting: 9
ok
0 of 2 examples failed in my_math.square.__doc__
1 items had no tests:
	test
1 items passed all tests:
2 tests in my_math.square
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

函数 testmod 检查模块的文档字符串和函数的文档字符串。

unittest

unittest (基于流行的Java测试框架JUnit)更灵活、更强大。

假设你要编写一个名为 my_math 的模块,其中包含一个计算乘积的函数 product 。

一个使用框架 unittest 的简单测试。

import unittest, my_math

class ProductTestCase(unittest.TestCase):

	def test_integers(self):
		for x in range(-10, 10):
			for y in range(-10, 10):
				p = my_math.product(x, y)
				self.assertEqual(p, x * y, 'Integer multiplication failed')

	def test_floats(self):
		for x in range(-10, 10):
			for y in range(-10, 10):
			x = x / 10
			y = y / 10
			p = my_math.product(x, y)
			self.assertEqual(p, x * y, 'Float multiplication failed')
			
if __name__ == '__main__': unittest.main()

函数 unittest.main 负责替你运行测试:实例化所有的 TestCase 子类,并运行所有名称以 test打头的方法。

运行这个测试脚本将引发异常,指出模块 my_math 不存在。

TestCase 类还包含很多与之类似的方法,如 assertTrue 、 assertIsNotNone 和 assertAlmostEqual 。

模块 unittest 区分错误失败
错误指的是引发了异常,而失败是调用 failUnless 等方法的结果。

超越单元测试

两个工具:源代码检查和性能分析。

源代码检查是一种发现代码中常见错误或问题的方式。

性能分析指的是搞清楚程序的运行速度到底有多快。

单元测试可让程序管用,源代码检查可让程序更好,而性能分析可让程序更快。

使用 PyChecker 和 PyLint 检查源代码

PyChecker(pychecker.sf.net)是用于检查Python源代码的唯一工具,能够找出诸如给函数提供的参数不对等错误。

PyLint(pylint.org),它支持PyChecker提供的大部分功能,还有很多其他的功能,如变量名是否符合指定的命名约定、你是否遵守了自己的编码标准等。

可以命令行脚本的方式运行它们(PyChecker和PyLint对应的脚本分别为pychecker 和 pylint ),也可将其作为Python模块(名称与前面相同)。

使用PyChecker来检查文件,可运行这个脚本并将文件名作为参数,如下所示:

pychecker file1.py file2.py ...

使用PyLint检查文件时,需要将模块(或包)名作为参数:

pylint module

PyChecker和PyLint都可作为模块(分别是 pychecker.checker 和 pylint.lint )导入。

导入 pychecker.checker 时,它会检查后续代码(包括导入
的模块),并将警告打印到标准输出。
模块 pylint.lint 包含一个函数 Run ,这个函数是供脚本 pylint 本身使用的。它也将警告打印出来,而不是以某种方式将其返回。

在Python中,可通过模块 subprocess 来使用命令行工具。

使用模块 subprocess 调用外部检查器。

import unittest, my_math
from subprocess import Popen, PIPE

class ProductTestCase(unittest.TestCase):
	#在这里插入以前的测试

	def test_with_PyChecker(self):
		cmd = 'pychecker', '-Q', my_math.__file__.rstrip('c')
		pychecker = Popen(cmd, stdout=PIPE, stderr=PIPE)
		self.assertEqual(pychecker.stdout.read(), '')

	def test_with_PyLint(self):
		cmd = 'pylint', '-rn', 'my_math'
		pylint = Popen(cmd, stdout=PIPE, stderr=PIPE)
		self.assertEqual(pylint.stdout.read(), '')
if __name__ == '__main__': unittest.main()

调用检查器脚本时,指定了一些命令行开关,以免无关的输出干扰测试。
对于 pychecker ,指定了开关 -Q (quiet,意为静默);
对于 pylint ,指定了开关 -rn (其中 n 表示no)以关闭报告,这意味着将只显示警告和错误。

性能分析

标准库包含一个性能分析模块 profile ,还有一个速度更快C语言版本,名为 cProfile 。
这个性能分析模块,只需调用其方法 run 并提供一个字符串参数。

>>> import cProfile
>>> from my_math import product
>>> cProfile.run('product(1, 2)')

然后,使用模块 pstats 来研究分析结果。

>>> import pstats
>>> p = pstats.Stats('my_math.profile')

小结

本章介绍的新函数

在这里插入图片描述

学习参考资料:

《Python基础教程》 第3版
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值