关于我
一个有思想的程序猿, 终身学习实践者, 目前在一个创业团队任 team lead, 技术栈涉及 Android,Python,Java 和 Go, 这个也是我们团队的主要技术栈.
GitHub: https://github.com/hylinux1024
微信公众号: 终身开发者 (angrycode)
也许你已经听说过 Test Driven Development, 但不知道你是否遵循这个规则呢? 其实我自己在写代码的时候也很少会先写单元测试再写业务功能逻辑. 这不我也今天也来学习如何在 Python 中写单元测试.
0x00 unittest
Python 中的 unittest 单元测试框架跟其它语言如 JUnit 是类似的. 它支持测试自动化, 配置共享以及关机代码测试.
假设在我的项目目录下有一个 mysum 模块用于计算列表中各个数之和.
还有一个 test_mysum.py 用于编写单元测试的文件.
myproject/
│
├── mysum/
│ └── __init__.py
└── unittests
└── test_mysum.py
打开 mysum 模块中的__init__.py 文件.
添加下面的方法
- def sum(args):
- total = 0
- for arg in args:
- total += arg
- return total
打开 test_mysum.py, 编写单元测试
- import unittest
- from mysum import sum
- class TestSum(unittest.TestCase):
- def test_list_int(self):
- """
- 测试一个整数列表的和
- """
- data = [1, 2, 3]
- result = sum(data)
- self.assertEqual(result, 6)
- if __name__ == '__main__':
- unittest.main()
首先导入我们要测试的模块 mysum
测试用例类通过继承 unittest.TestCase 来实现, 测试方法 test_list_int 是以 test 开头的.
在这个方法中定义了一个整型列表, 执行 sum 方法, 然后判断执行结果是否与预期相符.
最后调用 unittest.main() 来执行这个测试用例
- Ran 1 test in 0.001s
- OK
如果再添加一个方法
- def test_list_sum(self):
- data = [1, 3, 4]
- result = sum(data)
- self.assertEqual(result, 6)
执行后会看到如下类似信息
- 6 != 8
- Expected :8
- Actual :6
从这个输出信息可以看出期望值与实际值不相符, 这时候如果我们的测试用例没有问题, 那就要看看 mysum 的实现逻辑了.
从这个例子中可以总结一个测试用例的过程:
构建输入数据
执行要测试模块, 获取执行结果
与预期结果相比较, 根据结果修改代码
0x01 setup/tearDown
在编写单元测试时, 还可以重写父类的 setup 和 tearDown 方法, 可以在执行测试逻辑开始前和结束时做一些处理. 例如在 setup 方法中可以初始化测试数据, 在 tearDown 方法做一些清理工作.
- import unittest
- class TestBasic(unittest.TestCase):
- def setUp(self):
- # 加载测试数据
- self.App = App(database='fixtures/test_basic.json')
- def test_customer_count(self):
- self.assertEqual(len(self.App.customers), 100)
- def test_existence_of_customer(self):
- customer = self.App.get_customer(id=10)
- self.assertEqual(customer.name, "Org XYZ")
- self.assertEqual(customer.address, "10 Red Road, Reading")
- def tearDown(self):
- self.App.releaseDB()
在每个测试执行时 setup 和 tearDown 都会被执行一次.
0x02 pytest
pytest 是一个第三方测试框架, 使用它不需要继承某个类, 它可以使用原生的 assert 语句用于测试结果的断言.
它的用法也很简单
首先通过 pip 安装
pip install pytest
我们写一个单独的 tests 文件夹下创建测试用例文件 test_pytest.py.
注意: 这里 pytest 的文件必须与上文的 unittests 文件必须区分开, 否则会出现 ModuleNotFoundError. 我已经在这里踩坑.
我这里使用 pytest 单元测试的文件结构为
tests
│
└── test_func.py
test_func.py 的内容为
- # 导入我们要测试的模块
- from mysum import sum
- def test_answer():
- data = [1, 2, 3]
- assert sum(data) == 5
测试方法以 test 开头
然后再命令行中执行
python -m pytest tests/test_func.py
注意: 这里要使用 python -m pytest, 如果直接使用 pytest 会提示 ModuleNotFoundError: No module named 'mysum'
执行结果如下
- tests/test_func.py F [100%]
- ======================================================= FAILURES ==============================================
- _______________________________________________________ test_answer ___________________________________________
- def test_answer():
- data = [1, 2, 3]
- > assert sum(data) == 5
- E assert 6 == 5
- E + where 6 = sum([1, 2, 3])
- tests/test_func.py:11: AssertionError
- =======================================================1 failed in 0.03 seconds =======================================================
由于 6!=5, 这个单元测试提示了出错的位置.
0x03 总结一下
测试代码对编写代码非常重要, 写单元测试也是一个好习惯. 本文也只是一个开胃菜. 要写出健壮的代码, 从写单元测试开始吧.
0x04 学习资料
- https://docs.python.org/3/library/unittest.html
- Unit testing framework
- https://realpython.com/python-testing/
- Getting Started With Testing in Python
- https://docs.python-guide.org/writing/tests/
- Testing Your Code
来源: https://www.cnblogs.com/angrycode/p/11414618.html