以下主要是针对Python中使用配置、测试、日志介绍和示例。
Python3 配置
读取配置文件,我们这里使用configparser模块。
首先,我们来看一下配置文件的格式。
创建配置文件,可以通过一个文本文档来创建,或者在PyCharm的文件(File)菜单中新建(New)一个文件(File)。
配置文件的扩展名可以自定义,一般可以用“.ini”作为后缀,表示该文件是初始化文件(Initialization File)。
配置文件中类别的格式为:[类别名称]
配置项与其对应的值可以有两种格式:
配置项的名称 : 值
配置项的名称 = 值
配置文件内容示例:
[Size]
height : 768
width : 1024[Color]
background = 白色
border = 黑色
上面的配置文件包含了两个类别“Size”和“Color”,每个类别中都有两个配置项,采用两种不同的格式设置了对应的值。
接下来,我们就可以通过configparser模块来读取配置文件的信息。
示例代码:
import configparser # 导入模块
file = 'config.ini' # 指定文件路径
config = configparser.ConfigParser() # 实例化配置解析的类
config.read(file,encoding='utf-8') # 读取配置文件内容
print('程序界面宽度:', config.get('Size', 'width')) # 获取某一项配置的值
print('程序界面高度:', config.get('Size', 'height')) # 获取某一项配置的值
print('程序界面背景颜色:', config.get('Color', 'background')) # 获取某一项配置的值
print('程序界面边框颜色:', config.get('Color', 'border')) # 获取某一项配置的值
一般来说,配置文件是给程序的使用者使用的,比如通过配置文件更改图形界面程序的皮肤,或者通过配置文件隐藏显示某些功能等等。
Python3 测试
有一种开发方法叫测试驱动开发(Test-Driven Development)。
测试驱动开发的基本思想就是在开发功能代码之前,先编写测试代码,然后只编写使测试通过的功能代码,从而以测试来驱动整个开发过程的进行。
关于这种开发方法的具体细节,不是一两句话就能说清楚的。
测试一点代码,编写一点代码,可能不太好理解。
实际上,在测试代码中是要考虑到功能代码完成什么样的功能,以及种种可能出现的问题。
这样就规范了功能代码的实现范围,并且避免功能代码可预见问题的出现。
1、文档测试
文档测试需要使用doctest模块。
它可以通过代码文档中的交互式环境操作内容进行测试。
示例代码:
import doctest
'''
'>>>' 开头的行为测试用例,测试用例的下一行为测试用例的结果。
'''
def perimeter(r):
'''
计算圆形的周长。
:param r: 圆形半径的数值
:return: 圆形的周长
>>> perimeter(3)
18.85
'''
return round(2 * 3.14159 * r, 2)
if __name__ == '__main__':
doctest.testmod() # 运行测试
在上方代码中,我们能够看到perimeter()函数的文档中有如下两句:
>>> perimeter(3)
18.85
这两句内容就是我们在交互式环境中,调用perimeter()函数并传入参数的操作以及正确的结果。
doctest模块能够获取到这部分内容,执行测试。
当我们运行代码,没有发生错误时,只会有一条提示测试开始运行的信息:
Testing started at 12:47 …
而发生错误时(例如把圆周率数值改为3.14),在PyCharm中我们能够看到测试失败的数量和一些具体的测试信息。
2、单元测试
对于大型的测试,我们可以使用unittest模块。
通过继承unittest模块定义测试类,并在类中定义不同的方法对功能代码进行测试。
假设我们有一个计算面积的area模块。
模块中包含两个函数,用于计算圆形面积和矩形面积。
示例代码:
def circular(r): # 定义计算圆形面积的函数
return round(3.14 * r * 2, 2) # 注意:这个计算方法是错误的
def rectangle(w, h): # 定义计算矩形面积的函数
return w * h
然后,我们再创建一个用于测试的模块。
在测试模块中,我们就可以使用unittest模块编写测试组。
import unittest, area
class TestArea(unittest.TestCase): # 定义测试类,继承unittest模块的TestCase类
def test_circular(self): # 定义测试圆形面积计算函数的方法
rst = area.circular(2) # 调用被测试的函数,传入参数,获取计算结果。
self.assertEqual(rst, 3.14 * 4, '圆形的面积计算错误!')
# 比较计算结果和预置的结果是否相等,如果不相等则测试失败,给出自定义提示。
def test_rectangle(self): # 定义测试矩形面积计算函数的方法
rst = area.rectangle(3, 4) # 调用被测试的函数,传入参数,获取计算结果。
self.assertTrue(rst == 12, '矩形的面积计算错误!')
# 通过表达式判断计算结果与预定的结果是否相等,如果表达式返回值为False,则测试失败,给出自定义提示。
if __name__ == '__main__':
unittest.main() # 运行测试
上方代码中,写出了两种对被测试函数计算结果和预置结果进行比较的方法:
assertEqual()方法能够比较第1个参数和第2个参数是否相等,如果不相等则会给出测试失败的结果,并显示第3个参数中自定义的提示。
assertTrue()方法的第1个参数是表达式,如果表达式的结果是False,则会给出测试失败的结果,并显示第2个参数中自定义的提示。
而且,上方代码中每一个测试方法都是以“test”开头,这是必须的。
因为,运行测试的语句“unittest.main() ”只会自动运行测试类中所有以“test”开头的方法。
不过,上方的代码运行后虽然没有给出测试失败的提示,但是,其实计算圆形面积函数的计算方法是错误的,只不过刚好我们给的参数(2)无法发现错误。
当我们把测试的参数改为3,就会提示测试失败,显示提示信息:
(…省略了部分提示…)
AssertionError: 18.84 != 28.26 : 圆形的面积计算错误!
(…省略了部分提示…)
所以,当我们编写测试程序的时候,一定要考虑全面,尽量模拟出所有可能导致程序出现问题的情形。
另外,还要注意,这里的示例只是演示了模块的基本使用方法,在实际编程中测试不会这么简单。
Python3 日志
日志一般是用来记录程序运行相关的数据,也能在程序出现问题时帮我们排查错误。
接下来,我们使用logging模块来完成记录程序运行日志的功能。
日志文件通过logging模块中的basicConfig()函数创建,函数的第一个参数是日志记录的级别,第二个参数是日志文件的名称。
示例代码:
import logging, time
log_time = time.strftime('%Y-%m-%d', time.localtime(time.time())) # 获取当前日期
logging.basicConfig(level=logging.INFO, filename=log_time + '.log') # 创建日志文件
logging.info('%s 程序开始...' % time.ctime()) # 写入日志记录
try:
for i in range(-5, 5):
logging.info('正在计算 12 /%d ...' % i) # 写入日志记录
print(12 / i)
except Exception as e:
logging.info('发生错误:' + str(e)) # 写入日志记录
raise
logging.info('%s 程序结束...' % time.ctime()) # 写入日志记录
在上方代码中,程序的功能是除法计算,但会有零除的错误产生。
通过日志,我们就能够得到程序每一次运算过程的记录以及出错时的异常信息。
运行代码之后,会生成当天的日志文件,并记录内容。
日志内容如下:
INFO:root:Thu Dec 7 13:30:09 2017 程序开始…
INFO:root:正在计算 12 /-5 …
INFO:root:正在计算 12 /-4 …
INFO:root:正在计算 12 /-3 …
INFO:root:正在计算 12 /-2 …
INFO:root:正在计算 12 /-1 …
INFO:root:正在计算 12 /0 …
INFO:root:发生错误:division by zero