Python單元測試框架之pytest---如何執行測試用例
介紹
pytest是一個成熟的全功能的Python測試工具,可以幫助你寫出更好的程式。
適合從簡單的單元到複雜的功能測試
- l模組化parametrizeable裝置(在2.3,持續改進)
- l引數化測試函式(用例)
- l標記測試功能與屬性
- lSkip和xfail:處理不成功的測試用例(在2.4改進)
- l通過xdist外掛分發測試到多個CPU
- l不斷地重新執行失敗的測試
- l靈活約定的Python測試發現
HomePage:http://pytest.org
安裝
>pipinstall-Upytest#通過pip安裝
>py.test--version#檢視pytest版本
Thisispytestversion2.7.2,importedfromC:\Python27\lib\site-packages\pytest.pyc
簡單的測試
讓我們建立第一個檔案,對個簡單的功能進行測試。
#coding=utf-8 # 功能 def func(x): return x + 1 # 測試用例 def test_answer(): assert func(3) == 5
切換到測試檔案所在的目錄,通過“py.test”命令執行測試。
>py.test
執行結果如下圖:
===================================================================
在一個測試類中建立多個測試用例:
#coding=utf-8 class TestClass: def test_one(self): x = "this" assert "h" in x def test_two(self): x = "hello" assert x == "hi"
執行測試:
>py.test-qtest_class.py
-q為quiet。表示在安靜的模式輸出報告訴。加不加這個參有什麼區別呢?讀者可以對比一下兩次輸出的日誌。其實,就是少了一些pytest的版本資訊。
===================================================================
從Python程式碼中呼叫pytest
pytest中同樣提供了main()來函式來執行測試用例。
pytest/
├──test_sample.py
├──test_class.py
└──test_main.py
此目錄為我們練習的目錄,開啟test_mian.py
import pytest def test_main(): assert 5 != 5 if __name__ == '__main__': pytest.main()
直接執行該程式,sublime中按Ctrl+B執行。結果如下:
============================= test session starts ============================= platform win32 -- Python 2.7.10 -- py-1.4.30 -- pytest-2.7.2 rootdir: D:\pyse\pytest, inifile: collected 4 items test_class.py .F test_main.py F test_sample.py F ================================== FAILURES =================================== _____________________________ TestClass.test_two ______________________________ self = <test_class.TestClass instance at 0x000000000304F548> def test_two(self): x = "hello" > assert x == "hi" E assert 'hello' == 'hi' E - hello E + hi test_class.py:11: AssertionError __________________________________ test_main __________________________________ def test_main(): > assert 5 != 5 E assert 5 != 5 test_main.py:4: AssertionError _________________________________ test_answer _________________________________ def test_answer(): > assert func(3) == 5 E assert 4 == 5 E + where 4 = func(3) test_sample.py:9: AssertionError ===================== 3 failed, 1 passed in 0.03 seconds ====================== [Finished in 0.3s]
從執行結果看到,main()預設執行了當前檔案所在的目錄下的所有測試檔案。
那麼,如果我們只想執行某個測試檔案呢?可以向main()中新增引數,就像在cmd命令提示符下面一樣:
#coding=utf-8 import pytest def test_main(): assert 5 != 5 if __name__ == '__main__': pytest.main("-q test_main.py") # 指定測試檔案
執行結果:
F ================================== FAILURES =================================== __________________________________ test_main __________________________________ def test_main(): > assert 5 != 5 E assert 5 != 5 test_main.py:4: AssertionError 1 failed in 0.01 seconds
那如果我想執行某個目錄下的測試用例呢?指定測試目錄即可。
#coding=utf-8 import pytest def test_main(): assert 5 != 5 if __name__ == '__main__': pytest.main("d:/pyse/pytest/") # 指定測試目錄
建立執行測試指令碼
有時候我們的測試用例檔案分散在不同的層級目錄下,通過命令列的方式執行測試顯示不太方便,如何編寫一個執行所有測試用例的指令碼呢? pytest可以自動幫我們生成這樣的指令碼。
>py.test --genscript=runtests.py
開啟生成的測runtests.py檔案:
sources = """ eNrsve2S3EiSIDa3+jhtnvZ293Ra6SSdCZMUF0AzK1nk9OzM1nV2L4dNznKnm6TxY6dX1XVJVAJV halMIAkgWVU3O2d6Ar3CPYQeQn/1QjKTf8UnAplZ7O6ZPTNxpiszgQiPCA8PD3cPD/f/449+9/5H yds/W99M58v6fDqfl1XZzefv/9nbvxuPxxE8Oy+r8+jRy2dREq+bOt8siqaNo6zKo3hRV+1mRb/h a1UsuiKPPpRZdFncXNVN3qYRABmN3v/R23+OLbRd/v6/ePOf/tmPflSu1nXTRe1NOxotllnbRq+7 PKlPfwMw0qNR …… """ import sys import base64 import zlib class DictImporter(object): def __init__(self, sources): self.sources = sources def find_module(self, fullname, path=None): if fullname == "argparse" and sys.version_info >= (2,7): # we were generated with <python2.7 (which pulls in argparse) # but we are running now on a stdlib which has it, so use that. return None if fullname in self.sources: return self if fullname + '.__init__' in self.sources: return self return None def load_module(self, fullname): # print "load_module:", fullname from types import ModuleType try: s = self.sources[fullname] is_pkg = False except KeyError: s = self.sources[fullname + '.__init__'] is_pkg = True co = compile(s, fullname, 'exec') module = sys.modules.setdefault(fullname, ModuleType(fullname)) module.__file__ = "%s/%s" % (__file__, fullname) module.__loader__ = self if is_pkg: module.__path__ = [fullname] do_exec(co, module.__dict__) # noqa return sys.modules[fullname] def get_source(self, name): res = self.sources.get(name) if res is None: res = self.sources.get(name + '.__init__') return res if __name__ == "__main__": if sys.version_info >= (3, 0): exec("def do_exec(co, loc): exec(co, loc)\n") import pickle sources = sources.encode("ascii") # ensure bytes sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) else: import cPickle as pickle exec("def do_exec(co, loc): exec co in loc\n") sources = pickle.loads(zlib.decompress(base64.decodestring(sources))) importer = DictImporter(sources) sys.meta_path.insert(0, importer) entry = "import pytest; raise SystemExit(pytest.cmdline.main())" do_exec(entry, locals()) # noqa
好吧!其實, 我也不理解這段程式碼的含義,但是執行它的可執行測試用例了。
pytest/
├──test_case/
│├── test_sample.py
│├──test_class.py
│├── __init__.py
│ └──test_case2/
│ ├── test_main.py
│ ├── test_time.py
│ └──__init__.py
└──runtests.py
執行runtest.py檔案。
>python runtest.py
當然,你也可以開啟runtests.py 檔案執行它。