pytest單元測試框架fixture應用

fixture很是有用,它們提供了固定的基準,所以測試能夠被可靠地執行併產生一致的,可重複的結果。使用fixture能夠設置服務,狀態或其餘操做環境。測試函數經過參數調用fixture方法。json

fixture比setup、teardown等方法更好api

1.fixture具備明確的名稱,能夠經過在測試功能,模塊,類或整個項目中聲明其使用來激活。cookie

2.fixture以模塊的方式實現,由於每一個fixture方法都會觸發一個fixture功能,該功能自己可使用其餘fixture。session

3.fixture管理的範圍從簡單的單元測試到複雜的功能測試,能夠根據配置和組件選項對fixture和測試進行參數化,或者在功能,類,模塊或整個測試會話範圍內重複使用fixture。app

 

下面應用理解框架

使用測試程序函數

/testapi/add/單元測試

/testapi/minus/測試

/testapi/chengfa/url

 

使用pytest測試類

import pytest
import requests
import json
import os
import logging



class TestMath(object):
    @pytest.mark.parametrize('a,b',[(0.1,0.2),(1,2)])
    def testadd(self,a,b):
        '''測試加法程序'''
        headers = {
            'Content-Type': "application/json",
        }
        reqdata = {'a':a,'b':b}
        resp = requests.request(method='POST', url='http://127.0.0.1:8000/testapi/add/', verify=False, headers=headers, json=reqdata)

        resp = json.loads(resp.text)
        assert resp['status']==1
        assert resp['data'] == a + b
        return resp['data']

    @pytest.mark.parametrize('a,b',[(0.1,0.2),(1,2)])
    def testminus(self,a,b):
        '''測試加法程序'''
        headers = {
            'Content-Type': "application/json",
        }
        reqdata = {'a':a,'b':b}
        print(reqdata)
        resp = requests.request(method='POST', url='http://127.0.0.1:8000/testapi/minus/', verify=False, headers=headers, json=reqdata)
        resp = json.loads(resp.text)
        print(resp)
        assert resp['status']==1
        assert resp['data'] == a - b
        return resp['data']

    @pytest.mark.parametrize('a,b',[(0.1,0.2),(1,2)])
    def testchengfa(self,a,b):
        '''測試加法程序'''
        headers = {
            'Content-Type': "application/json",
        }
        reqdata = {'a':a,'b':b}
        print(reqdata)
        resp = requests.request(method='POST', url='http://127.0.0.1:8000/testapi/chengfa/', verify=False, headers=headers, json=reqdata)
        # warnings.warn('這是個警告', category=None, stacklevel=1, source=None)
        resp = json.loads(resp.text)
        print(resp)
        assert resp['status']==1
        assert resp['data'] == a * b
        return resp['data']

if __name__ == '__main__':
    pytest.main(['D:/PycharmProjects/untitled/test_math.py'])

 

好比說要使用cookie,通常來講是須要初始化

@pytest.fixture
def mycookie(self):
self.s = requests.session()
c = requests.cookies.RequestsCookieJar()
c.set('testcookies', 'XXXXXXX')
self.s.cookies.update(c)
return self.s

測試方法中加入print(mycookie.cookies['testcookies'])

運行看見能打印XXXXXXX

 

conftest.py

若是在實施測試期間您意識到要使用fixture到多個測試文件中的功能,則能夠將其移至一個conftest.py文件中。測試中無需在全部文件導入這個fixture,它會被pytest自動發現。夾具功能的發現始於測試類,而後是測試模塊,而後是 conftest.py文件,最後是內置插件和第三方插件。

fixture做用範圍

夾具是在測試首次請求時建立的,並根據如下scope的值決定fixture什麼時候被銷燬:

function:默認範圍,fixture在單個測試對象運行結束時被銷燬。

class:在class中的最後一個測試對象運行完被銷燬。

module:在文件中的最後一個測試對象運行完被銷燬。

package:在包中的最後一個測試對象運行完被銷燬。

session:在整個測試階段結束時被銷燬。

 

import pytest

# fixtures documentation order example
order = []


@pytest.fixture(scope="session")
def s1():
    order.append("s1")


@pytest.fixture(scope="module")
def m1():
    order.append("m1")


@pytest.fixture
def f1(f3):
    order.append("f1")


@pytest.fixture
def f3():
    order.append("f3")


@pytest.fixture(autouse=True)
def a1():
    order.append("a1")


@pytest.fixture
def f2():
    order.append("f2")


def test_order(f1, m1, f2, s1):
    assert order == ["s1", "m1", "a1", "f3", "f1", "f2"]

test_order調用的fixture將按如下順序實例化:

s1:session是外面一層。

m1:module是第二外面一層。

a1:是一個autouse-fixture:它會在同一範圍內的其它fixture以前被實例化。

f3:被同級別調用的比調用者先實例化

f1:同級別按排名順序調用

f2:同上

 

使用fixture代替setup/teardown

經過使用yield語句代替returnyield語句以後的全部代碼都將用做teardown的功能。

例如登陸和退出

    @pytest.fixture(scope='module',autouse=True)
    def logginandout(self):
        print('登陸成功')
        yield
        print('退出成功')
test_math.py::TestMath::testadd[0.1-0.2] 登陸成功
...
FAILED退出成功

改爲scope='function'的話

test_math.py::TestMath::testadd[0.1-0.2] 登陸成功
XXXXXXX
PASSED退出成功

test_math.py::TestMath::testadd[1-2] 登陸成功
XXXXXXX
PASSED退出成功

test_math.py::TestMath::testminus[0.1-0.2] 登陸成功
{'a': 0.1, 'b': 0.2}
{'status': 1, 'message': '請求成功', 'data': -0.1}
PASSED退出成功

test_math.py::TestMath::testminus[1-2] 登陸成功
{'a': 1, 'b': 2}
{'status': 1, 'message': '請求成功', 'data': -1}
PASSED退出成功

test_math.py::TestMath::testchengfa[0.1-0.2] 登陸成功
{'a': 0.1, 'b': 0.2}
{'status': 1, 'message': '請求成功', 'data': 0.30000000000000004}
FAILED退出成功

test_math.py::TestMath::testchengfa[1-2] 登陸成功
{'a': 1, 'b': 2}
{'status': 1, 'message': '請求成功', 'data': 3}
FAILED退出成功

fixture參數化

能夠對fixture功能進行參數設置,在這種狀況下,它們將被屢次調用,每次執行一組相關測試,即依賴於該fixture的測試夾具參數化有助於爲組件編寫詳盡的功能測試,這些組件自己能夠經過多種方式進行配置。

    @pytest.fixture(params= [(0.1,0.2),(1,2)],ids=['小數','整數'])
    def gettestdata(self,request):
        return request.param

加入以上fixture並修改測試方法

    # @pytest.mark.parametrize('a,b',[(0.1,0.2),(1,2)])
    def testadd(self,gettestdata,mycookie):
        '''測試加法程序'''
        print(mycookie.cookies['testcookies'])
        a,b = gettestdata[0],gettestdata[1]
        headers = {
            'Content-Type': "application/json",
        }
        reqdata = {'a':a,'b':b}
        resp = mycookie.request(method='POST', url='http://127.0.0.1:8000/testapi/add/', verify=False, headers=headers, json=reqdata)
        resp = json.loads(resp.text)
        assert resp['status']==1
        assert resp['data'] == a + b
        return resp['data']
...

pytest.main(['-v',''])運行成功

test_math.py::TestMath::testadd[小數] PASSED [ 16%]
test_math.py::TestMath::testadd[整數] PASSED [ 33%]
test_math.py::TestMath::testminus[小數] PASSED [ 50%]
test_math.py::TestMath::testminus[整數] PASSED [ 66%]
test_math.py::TestMath::testchengfa[小數] FAILED [ 83%]
test_math.py::TestMath::testchengfa[整數] FAILED [100%]

注意加入scope='class'順序不一樣

test_math.py::TestMath::testadd[小數] PASSED                             [ 16%]
test_math.py::TestMath::testminus[小數] PASSED                           [ 33%]
test_math.py::TestMath::testchengfa[小數] FAILED                         [ 50%]
test_math.py::TestMath::testadd[整數] PASSED                             [ 66%]
test_math.py::TestMath::testminus[整數] PASSED                           [ 83%]
test_math.py::TestMath::testchengfa[整數] FAILED                         [100%]

加入scope='function'

test_math.py::TestMath::testadd[小數] PASSED                             [ 16%]
test_math.py::TestMath::testadd[整數] PASSED                             [ 33%]
test_math.py::TestMath::testminus[小數] PASSED                           [ 50%]
test_math.py::TestMath::testminus[整數] PASSED                           [ 66%]
test_math.py::TestMath::testchengfa[小數] FAILED                         [ 83%]
test_math.py::TestMath::testchengfa[整數] FAILED                         [100%]

使用usefixtures

有時測試功能不須要直接訪問fixture對象。使用@pytest.mark.usefixtures直接調用

# conftest.py

@pytest.fixture()
def writelog(self):
    try:
        self.resultfile = open('testtext.txt', 'w+', encoding='utf-8')
    except Exception as e:
        pass
    if self.resultfile.writable():
        self.resultfile.writelines('測試開始!')
        self.resultfile.writelines('\n')
        yield
        self.resultfile.writelines('測試結束!')
        self.resultfile.writelines('\n')
    self.resultfile.close()

    測試類以前加上@pytest.mark.usefixtures('writelog')就能寫入文件

測試開始!
測試結束!

能夠指定多個燈具

能夠將項目中全部測試所需的燈具放入ini文件中

# content of pytest.ini
[pytest]
usefixtures = writelog

使用fixture讀取excel文件參數進行測試

加入Excel進行測試是比較常規的參數化作法

 

 

 

首先加入讀取excel方法

    def getdata(cls):
        file = xlrd.open_workbook('test.xlsx')
        sheet = file.sheet_by_index(0)
        rownum = file.sheet_by_index(0).nrows
        ablist = []
        for row in range(rownum):
            if row:
                rowvalue = sheet.row_values(row)
                ablist.append((rowvalue[2], rowvalue[3]))
        return ablist
        #ablist = [(0.1, 0.2), (1.0, 2.0), (0.1, 2.0)]

而後用fixture調用此方法

    @pytest.fixture(params= getdata('TestMath'))
    def gettestdata(self,request):
        print('參數' + str(request.param))
        return request.param

查看運行結果

test_math.py::TestMath::testadd[gettestdata0] PASSED                     [ 11%]
test_math.py::TestMath::testadd[gettestdata1] PASSED                     [ 22%]
test_math.py::TestMath::testadd[gettestdata2] PASSED                     [ 33%]
test_math.py::TestMath::testminus[gettestdata0] PASSED                   [ 44%]
test_math.py::TestMath::testminus[gettestdata1] PASSED                   [ 55%]
test_math.py::TestMath::testminus[gettestdata2] PASSED                   [ 66%]
test_math.py::TestMath::testchengfa[gettestdata0] FAILED                 [ 77%]
test_math.py::TestMath::testchengfa[gettestdata1] FAILED                 [ 88%]
test_math.py::TestMath::testchengfa[gettestdata2] FAILED                 [100%]

標籤很差看,添加一下ids

    def getdata(cls):
        file = xlrd.open_workbook('test.xlsx')
        sheet = file.sheet_by_index(0)
        rownum = file.sheet_by_index(0).nrows
        title = []
        ablist = []
        for row in range(rownum):
            if row:
                rowvalue = sheet.row_values(row)
                title.append(rowvalue[1])
                ablist.append((rowvalue[2], rowvalue[3]))
        return (title,ablist)

修改成@pytest.fixture(params= getdata('TestMath')[1],ids=getdata('TestMath')[0],在運行看運行結果

test_math.py::TestMath::testadd[兩個小數] PASSED                         [ 11%]
test_math.py::TestMath::testadd[兩個整數] PASSED                         [ 22%]
test_math.py::TestMath::testadd[小數和整數] PASSED                       [ 33%]
test_math.py::TestMath::testminus[兩個小數] PASSED                       [ 44%]
test_math.py::TestMath::testminus[兩個整數] PASSED                       [ 55%]
test_math.py::TestMath::testminus[小數和整數] PASSED                     [ 66%]
test_math.py::TestMath::testchengfa[兩個小數] FAILED                     [ 77%]
test_math.py::TestMath::testchengfa[兩個整數] FAILED                     [ 88%]
test_math.py::TestMath::testchengfa[小數和整數] FAILED                   [100%]

漂亮不少

添加參數scope='module'運行查看結果,運行順序有變化,說明默認爲scope='function',pytest框架尋找每一個方法調用參數,scope='class',pytest框架尋找每一個類調用參數,以此類推

test_math.py::TestMath::testadd[兩個小數] PASSED                         [ 11%]
test_math.py::TestMath::testminus[兩個小數] PASSED                       [ 22%]
test_math.py::TestMath::testchengfa[兩個小數] FAILED                     [ 33%]
test_math.py::TestMath::testadd[兩個整數] PASSED                         [ 44%]
test_math.py::TestMath::testminus[兩個整數] PASSED                       [ 55%]
test_math.py::TestMath::testchengfa[兩個整數] FAILED                     [ 66%]
test_math.py::TestMath::testadd[小數和整數] PASSED                       [ 77%]
test_math.py::TestMath::testminus[小數和整數] PASSED                     [ 88%]
test_math.py::TestMath::testchengfa[小數和整數] FAILED                   [100%]
相關文章
相關標籤/搜索