《python编程从入门到实践》读书实践笔记(二)


本文是《python编程从入门到实践》读书实践笔记11章的内容,主要包含测试,为体现测试的重要性,独立成文。

11 测试代码

写在前面的话,以下是我这些年开发中和测试相关的血泪史。

  • 对于一个bug,发现得越晚,处理它的成本就越高。
  • bug在一个复杂系统中时,找到它要比处理它麻烦的多。
  • 大多数bug都低级得令人发指。
  • 永远无法找到所有bug,成本和安全需要互相妥协,极端一般都不那么美好。
  • 测试人员有他们的KPI,自己找的bug才适合自己

11.1函数自测、测试用例和unittest

Python标准库unittest提供了代码测试工具,可以用于代码的单元测试。
如果要用unnitest,需要建一个unittest的类
比如,当前有一个函数,该函数被存在city_function.py中

def city_country(city, country, polulation=None):
    """根据输入的城市,国家,人口,返回特定格式字符串"""
    if polulation == None:
        city_country_rst = f"{city.title()}, {country.title()}"
    elif polulation is not None:
        city_country_rst = f"{city.title()}, {country.title()} - polulation {polulation}"
    return city_country_rst

再新建一个test_cities.py的文件,以进行对刚才函数的测试

import unittest
from city_function import *

class CityFuncTestCase(unittest.TestCase):
    """测试city_function.py"""

    def test_city_country_only_func(self):
        """能够正确地得到结果"""
        city_country_rst = city_country('shanghai', 'china')
        self.assertEqual(city_country_rst, 'Shanghai, China')

    def test_city_country_polulation_func(self):
        """能够正确地得到结果"""
        city_country_rst = city_country('shanghai', 'china', 16_0000_0000)
        self.assertEqual(city_country_rst, 'Shanghai, China - polulation 1600000000')


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

对于CityfuncTestCase类,其中的子函数(每一个测试用例)必须以test_开头,这样才能在运行unitest.main()时自动调用这些测试用例。
如果一个函数的外部交互较少,可以在测试时适当减少用例。比如在这个city_country函数中,就没有增加polulation数值范围的校验。

11.2 类自测

类测试和函数测试几乎一样,都是在unittest中新建一个类,来测试需要的方法或属性

11.2.4 方法setUp()

可以通过在测试类(比如刚才的CityFuncTestCase)中,增加setUp()方法,来在每一个测试用例调用前,增加一些相同的操作。对应的tearDown()方法中的内容会在每一个测试用例调用后执行。

被测试的类,保存在classEmployee.py中

class Employee():
    """记录雇员的信息"""
    def __init__(self, name, salary=2000):
        self.name = name
        self.salary = salary

    def give_raise(self, amount=500):
        self.salary += amount

测试脚本test_classEmployee.py:

import unittest
from classEmployee import *

class testClassEmployee(unittest.TestCase):
    """针对Employee类的测试"""

    def setUp(self):
        """创建一个员工,用于测试"""
        self.default_emp = Employee('Zhangsan')
        self.sp_emp = Employee('Lisi', salary=5000)

    def test_default_new_employee(self):
        """测试默认薪水下的普通员工"""
        self.assertEqual(self.default_emp.salary, 2000)

    def test_sp_new_employee_with_salary_5000(self):
        """测试特定薪水下的新建员工"""
        self.assertEqual(self.sp_emp.salary, 5000)

    def test_employee_give_raise_default(self):
        """测试默认薪水下的普通员工"""
        self.default_emp.give_raise()
        self.assertEqual(self.default_emp.salary, 2500)

    def test_employee_give_raise_2000(self):
        """测试默认薪水下的普通员工"""
        self.default_emp.give_raise(amount=2000)
        self.assertEqual(self.default_emp.salary, 4000)


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

通过test_employee_give_raise_default()和test_employee_give_raise_2000()可以发现,单元测试的函数间是不会互相影响的。(这两个函数都对self.default_emp进行了操作,但是这些操作并不互通)

unittest的其他信息

最全面的肯定是python关于unittest的官方文档
其他一些blog也可以看起来,当然最主要的还是:

  1. 自测的愿望
  2. 在实践中不断使用

后话

unittest只是python标准库中的自测框架,其实还有一些框架可以选用。