doctest, unittest, nose, pytest
內建: n/a
標準:
- doctest
- unittest
第三方:
- pytest
- nose
- nose2
- 比較
- google trend 分析結果顯示 nose 近來已被 pytest 超越. nose2 普及率仍不及前兩者
- nose2 is not nose
Test Runner Wrapper:
- python manage.py test (django 專案專用)
- python setup.py test
- 安裝 pytest or nose 後會自動擴充 setup.py 命令, 新增一個 test 命令
- nosetests (由套件 nose 提供)
- py.test (由套件 pytest 提供)
- runtests.py (由套件 pytest 提供)
其他
- unittest2 (舊版 python 專用)
- testr (openstack 專案專用)
doctest
(1) 單元代碼, 測試腳本, test runner 都寫在 source.py
source.py
"""
>>> add(1, 1)
2
"""
def add(x, y):
return x+y
if __name__ == '__main__':
import doctest
doctes.testmod()
run
python source.py -v
(2) 單元代碼, 測試腳本寫在 source.py (我比較喜歡 2-2 這種形式)
source.py (2-1)
"""
>>> add(1, 1)
2
"""
def add(x, y):
return x+y
or (2-2)
def add(x, y):
"""
>>> add(1, 1)
2
"""
return x+y
run
python -m doctest -v source.py
(3) 單元代碼寫在 source.py; 測試腳本寫在 test.txt
source.py
def add(x, y):
return x+y
test.txt
>>> from source import add
>>> add(1, 1)
2
run
python -m doctest -v test.txt
(4) 單元代碼, test runner 寫在 source.py; 測試腳本寫在 test.txt
source.py
def add(x, y):
return x+y
if __name__ == '__main__':
import doctest
doctes.testfile('test.txt')
test.txt
>>> from source import add
>>> add(1, 1)
2
run
python source.py -v
unittest
(1) 單元代碼, 測試腳本, test runner 都寫在 source.py
source.py
def add(x, y):
return x+y
import unittest
class AddTestCase(unittest.TestCase):
def test_add(self):
self.aseertEqual(add(1, 1), 2)
if __name__ == '__main__':
unittest.main()
run
python source.py -v
(2) 單元代碼, 測試腳本寫在 source.py
source.py
def add(x, y):
return x+y
import unittest
class AddTestCase(unittest.TestCase):
def test_add(self):
self.aseertEqual(add(1, 1), 2)
run
python -m unittest -v source
(3) 單元代碼寫在 source.py; 測試腳本寫在 test.py (我比較喜歡這種形式)
source.py
def add(x, y):
return x+y
test.py
from source import add
import unittest
class AddTestCase(unittest.TestCase):
def test_add(self):
self.aseertEqual(add(1, 1), 2)
run (3-1)
python -m unittest -v test # 3-1-1
python -m unittest -v test.AddTestCase # 3-1-2
python -m unittest -v test.AddTestCase.test_add # 3-1-3
or (3-2)
python -m unittest discover -v # discover 預設會搜尋並執行 test*.py
參考資料
- https://docs.python.org/2.7/library/unittest.html
- http://www.codedata.com.tw/python/python-tutorial-the-6th-class-1-unittest/
- https://imsardine.wordpress.com/tech/unit-testing-in-python/
重點摘要
- 定義一個繼承 unittest.TestCase 的子類別 , 通常命名為 xxxxTestCase
- 在自定義的子類別中撰寫一或多個 test_oooo(self) 測試方法 , 一個方法代表一個測試
- 測試方法中如果需要資源 (測試設備) 的取得與釋放, 可以在特殊方法 setUp(self) 和 tearDown(self) 中處理
- 為了確保 test isolation,每一個 test method 都是透過一個全新的 TestCase 來執行
pytest
- py.test
- runtests.py (deprecated since version 2.8)
- python setup.py test
(1) 單元代碼, 測試腳本, test runner 都寫在 source.py
n/a
(2) 單元代碼, 測試腳本寫在 source.py
n/a
(3) 單元代碼寫在 source.py; 測試腳本寫在 test_add.py 或 add_test.py
source.py
def add(x, y):
return x+y
test_add.py 或 add_test.py
from source import add
def test_add():
assert add(1, 1) == 2
run (3-1)
py.test test_add.py
or (3-2)
py.test # 預設會搜尋並執行 test_*.py 或 *_test.py
python runtests.py
py.test --genscript=runtests.py
python runtests.py
python setup.py test
# setup.py
from setuptools import setup
setup(
setup_requires=['pytest-runner',],
tests_require=['pytest',],
)
# setup.cfg
[aliases]
test=pytest
python setup.py test
排名 | 項目 | nose | pytest | 說明 |
---|---|---|---|---|
- | google-api-python-client | Y | - | unittest2,mock |
- | horizon | - | - | manage.py test |
- | python-novaclient | - | - | testr |
1 | django | - | - | - |
2 | requests | - | Y | - |
3 | httpie | - | Y | - |
4 | flask | - | Y | - |
5 | tornado | - | - | unittest2,mock |
6 | ansible | Y | - | unittest2,mock |
8 | sentry | - | - | mock |
9 | scrapy | - | Y | mock |
13 | ipython | Y | - | - |
17 | salt | - | - | - |
Workshop: Test-Driven Web Development with Django
http://test-driven-django-development.readthedocs.io/en/latest/index.html
Test-Driven Django Tutorial
http://www.tdd-django-tutorial.com/
Faster Django Testing
http://tech.marksblogg.com/faster-django-testing.html
Changing Django cache backend between test cases
http://www.2general.com/blog/2012/08/09/changing_django_cache_backend_between_test_cases.html
Python Mocking 101: Fake It Before You Make It
https://blog.fugue.co/2016-02-11-python-mocking-101.html
An Introduction to Mocking in Python
https://www.toptal.com/python/an-introduction-to-mocking-in-python
Small Testing Guide
https://wiki.openstack.org/wiki/SmallTestingGuide
Django 內建的測試框架繼承自 Python 內建的 unittest 模組
參考資料
重點摘要
- from django.test import TestCase 或 from unittest import TestCase
- If your tests rely on database access such as creating or querying models, be sure to create your test classes as subclasses of django.test.TestCase rather than unittest.TestCase.
- Using unittest.TestCase avoids the cost of running each test in a transaction and flushing the database, but if your tests interact with the database their behavior will vary based on the order that the test runner executes them. This can lead to unit tests that pass when run in isolation but fail when run in a suite.