測(cè)試的常用規(guī)則
- 一個(gè)測(cè)試單元必須關(guān)注一個(gè)很小的功能函數(shù),證明它是正確的;
- 每個(gè)測(cè)試單元必須是完全獨(dú)立的,必須能單獨(dú)運(yùn)行。這樣意味著每一個(gè)測(cè)試方法必須重新加載數(shù)據(jù),執(zhí)行完畢后做一些清理工作。通常通過(guò)setUp()和setDown()方法處理;
- 編寫執(zhí)行快速的測(cè)試代碼。在某些情況下,測(cè)試需要加載復(fù)雜的數(shù)據(jù)結(jié)構(gòu),而且每次執(zhí)行的時(shí)候都要重新加載,這個(gè)時(shí)候測(cè)試執(zhí)行會(huì)很慢。因此,在這種情況下,可以將這種測(cè)試放置一個(gè)后臺(tái)的任務(wù)中。
- 采用測(cè)試工具并且學(xué)著怎么使用它。
- 在編寫代碼前執(zhí)行完整的測(cè)試,而且在編寫代碼后再重新執(zhí)行一次。這樣能保證你后來(lái)編寫的代碼不會(huì)破壞任何事情;
- 在提交代碼前執(zhí)行完整的測(cè)試;
- 如果在開(kāi)發(fā)期間被打斷了工作,寫一個(gè)打斷的單元測(cè)試,關(guān)于你下一步將要開(kāi)發(fā)的。當(dāng)你回來(lái)工作時(shí),你能知道上一步開(kāi)發(fā)到的指針;
- 單元測(cè)試函數(shù)使用長(zhǎng)的而且具有描述性的名字。在正式執(zhí)行代碼中,可能使用square()或sqr()取名,但是在測(cè)試函數(shù)中,你必須取像test_square_of_number_2()、test_square_negativer_number()這些名字,這些名字描述更加清楚;
- 測(cè)試代碼必須具有可讀性;
- 單元測(cè)試對(duì)新進(jìn)的開(kāi)發(fā)人員來(lái)說(shuō)是工作指南。
單元測(cè)試的目的是對(duì)一個(gè)模塊、一個(gè)函數(shù)或者一個(gè)類來(lái)進(jìn)行正確性檢驗(yàn),如果單元測(cè)試通過(guò),說(shuō)明我們測(cè)試的對(duì)象能夠正常工作。如果單元測(cè)試不通過(guò),要么測(cè)試對(duì)象有 bug,要么測(cè)試條件輸入不正確。下面小編為大家介紹 Python 的幾種測(cè)試框架。
推薦好課:Python 自動(dòng)化管理、Python 自動(dòng)化辦公。
1. unittest
unittest 和 JUnit類似,可以說(shuō)是python的標(biāo)準(zhǔn)單元測(cè)試框架,所以有時(shí)也被人稱為 PyUnit。它使用起來(lái)和xUnit 家族其他成員類似。 用的人也比較多。兼容 python2 以及python3 。
個(gè)人比較喜歡用這個(gè),主要之前用過(guò)JUnit,用這個(gè)上手就很快。而且屬于python自動(dòng)集成,不用額外的安裝包,感覺(jué)是該有的都有了,用著方便。
示例:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
2. unittest2
unittest2 可以說(shuō)是一個(gè)針對(duì) unittest 測(cè)試框架新特性的補(bǔ)丁。它很大程度上和 unittest 都類似。然后還添加了一些 unittest 沒(méi)有的方法。
3. pytest
參考文檔:http://pytest.org/latest/
看了一下,pytest文檔還是蠻詳細(xì)的。比較關(guān)注的一點(diǎn)是,pytest 直接可以通過(guò) @pytest.mark.parametrize 進(jìn)行參數(shù)化,而unittest 則需要借助DDT。
示例:
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 5
執(zhí)行如下:
$ pytest
======= test session starts ========
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item
test_sample.py F
======= FAILURES ========
_______ test_answer ________
def test_answer():
> assert inc(3) == 5
E assert 4 == 5
E + where 4 = inc(3)
test_sample.py:5: AssertionError
======= 1 failed in 0.12 seconds ========
4. nose
nose 擴(kuò)展了 unittest,從而使得測(cè)試更容易。
一般可以用 unittest 方式寫用例,寫完之后用 nose 來(lái)執(zhí)行。nose 的測(cè)試收集方式還是很方便的。
還有一個(gè)特定就是,nose 可以采用 @with_setup() 來(lái)定義方法的 setup 和 teardown。
示例:
def setup_func():
"set up test fixtures"
def teardown_func():
"tear down test fixtures"
@with_setup(setup_func, teardown_func)
def test():
"test ..."
5. doctest
doctest 模塊會(huì)搜索那些看起來(lái)像交互式會(huì)話的 Python 代碼片段,然后嘗試執(zhí)行并驗(yàn)證結(jié)果。
doctest 中,如果要寫測(cè)試用例,只需要在寫在以 ''' '''包圍的文檔注釋即可,也就是可以被__doc__這個(gè)屬性引用到的地方。這點(diǎn)比較特別,跟其他單元測(cè)試框架都不一樣。但是我覺(jué)得這樣的話就注定了doctest不適合大型測(cè)試,因?yàn)樽霾坏酱a和測(cè)試的分離。
import doctest
"""
This is the "example" module.
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
if __name__ == "__main__":
doctest.testmod(verbose=True)
verbose 參數(shù)用于控制是否輸出詳細(xì)信息,默認(rèn)為 False ,如果不寫,那么運(yùn)行時(shí)不會(huì)輸出任何東西,除非測(cè)試 fail。
輸出如下:
Trying:
[factorial(n) for n in range(6)]
Expecting:
[1, 1, 2, 6, 24, 120]
ok
Trying:
factorial(30)
Expecting:
265252859812191058636308480000000
ok
Trying:
factorial(-1)
Expecting:
Traceback (most recent call last):
...
ValueError: n must be >= 0
ok
Trying:
factorial(30.1)
Expecting:
Traceback (most recent call last):
...
ValueError: n must be exact integer
ok
Trying:
factorial(30.0)
Expecting:
265252859812191058636308480000000
ok
Trying:
factorial(1e100)
Expecting:
Traceback (most recent call last):
...
OverflowError: n too large
ok
1 items had no tests:
__main__
1 items passed all tests:
6 tests in __main__.factorial
6 tests in 2 items.
6 passed and 0 failed.
Test passed.