1. 程式人生 > 其它 >Python單元測試框架之pytest---如何執行測試用例

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 檔案執行它。