淺談如何提升自動化測試的穩定性和可維護性 (pytest&allure)

裝飾器與出錯重試機制

談到穩定性,不得不說的就是「出錯重試」機制了,在自動化測試中,因爲環境通常都是測試環境,常常會有各類各類的抽風狀況影響測試結果,這樣就爲測試的穩定性帶來了挑戰,畢竟誰也不想本身的腳本一天到晚的出各類未知問題,而每每這種環境的抽風(一般是前端頁面的響應速度和後端接口的響應速度)帶來的影響是暫時的,可能上一秒失敗了,下一秒你再執行又好了,在這種狀況下,若是你有一個出錯重試機制,起碼能夠在這種暫時性的影響下讓你的腳本安然無恙,下面咱們具體的說一下作法。前端

什麼是裝飾器?

由於咱們的作法依賴裝飾器,因此在去作以前,先簡單介紹一下裝飾器。python

裝飾器,表現形式爲,在方法(或者類)的上面加上@xxx這樣的語句,假如咱們已經實現了一個裝飾器名叫retry,那麼咱們想用它就這麼用:git

@retry
def test_login():
    print("test")
    error = 1/0

若是retry實現了出錯再次重試(稍後再說如何實現),那麼這麼使用的話,就會讓test_login這個case在執行出錯的時候再次執行。github

很神奇,讓咱們來看看實現retry的代碼:面試

def retry(func):
    def warp():
        for time in range(3):
            try:
                func()
            except:
                pass
    return warp

就結果而言,執行如下代碼:後端

@retry
def test_login():
    print("test")
    error = 1/0

test_login()

和執行:閉包

retry(test_login)()

是等價的,由此咱們能夠看出,裝飾器其實本質上就是一個函數,這個函數接收其餘函數(或者類)做爲參數,經過對這個函數(或者類)的調用或者修改,完成不更改原始函數而修改該函數的功能。框架

在這裏還有一個知識點,你有沒有想過,在retry內部的函數warp(),是怎麼拿到func這個參數來執行的?執行retry函數return的是warp這個函數,而warp並無接受func這個傳參啊。dom

這就是python裏的閉包的概念,閉包就是指運行時自帶上下文的函數,好比這裏的warp這個函數,他運行的時候自帶了上層函數retry傳給他的func這個函數,因此才能夠在運行時對func進行處理和輸出。函數

瞭解了裝飾器和閉包,那麼下面就很容易作到對測試用例的出錯重試機制了。

若是對軟件測試、接口測試、自動化測試、性能測試、LR腳本開發、面試經驗交流。感興趣能夠來加羣:747981058,羣內會有不按期的發放免費的資料連接,這些資料都是從各個技術網站蒐集、整理出來的,若是你有好的學習資料能夠私聊發我,我會註明出處以後分享給你們。

編寫一個出錯重試裝飾器

如今,咱們來嘗試本身編寫一個用於測試用例的出錯重試裝飾器,代碼以下:

def retry(times=3,wait_time=10):
    def warp_func(func):
        def fild_retry(*args,**kwargs):
            for time in range(times):
                try:
                    func(*args,**kwargs)
                    return 
                except:
                    time.sleep(wait_time)
        return fild_retry
    return warp_func

這個裝飾器能夠經過傳入重試次數(times)和重試等待時間(wait_time),對待測用例實行重試機制。

pytest裏的出錯重試機制實現

在測試框架pytest裏,已經實現了有關出錯重試的策略,咱們首先須要安裝一個此類的插件,在cmd內執行如下命令安裝:

pip install pytest-rerunfailures

若是你須要將此機制應用到全部的用例上,那麼請在執行的時候使用以下命令(reruns是重試次數):

pytest --reruns 5

來執行你的用例;

若是你指望加上出錯重試的等待時間,請使用以下命令(reruns-delay是等待時間):

pytest --reruns 5 --reruns-delay 1

來執行你的用例;

若是你只想對某幾個測試用例應用重試策略,你可使用裝飾器:

@pytest.mark.flaky(reruns=5, reruns_delay=2)

例如:

@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_example():
    import random
    assert random.choice([True, False])

更詳細的介紹請參閱官方文檔 。

Allure裏的測試用例分層

剛剛咱們實現了用例的出錯重試機制,可是這僅僅解決了腳本在不穩定環境下的穩定性;若是還想要腳本變得更加容易維護,除了傳統的po模式使用例和元素分離以外,咱們還能夠引入測試用例分層機制。

爲何要採用分層機制?

傳統的po模式,僅僅實現了用例和元素分離,這必定層面上保障了用例的可維護性,起碼沒必要頭疼於元素的變動會讓用例處處失效;可是這還不夠,例如,如今有三個case,他們都包含了如下步驟:登陸、打開工做臺、進入我的中心;那麼若是不作分層,這三個用例會把這三個步驟都寫一遍,若是某天頁面的變更致使其中一個步驟須要更改,那麼你不得不去每一個用例裏去更新那個步驟。

而若是,咱們把用例當作是堆積木,登陸、打開工做臺、進入我的中心這三個步驟都只是個積木,那麼咱們寫用例的時候,只須要在用到這個步驟時,把積木搭上去;若是某一天,其中一個積木的步驟有變更,那麼只須要去更改這個積木的內容,而無需在每一個使用了這個積木的用例裏去改動。

這大大加強了用例的複用性和可維護性,這就是採用分層機制的緣由,下面,我會就allure裏的分層機制作介紹來討論具體如何實現。

allure的裝飾器@step

在allure裏,咱們能夠經過裝飾器@step完成分層機制,具體的,當你用@step裝飾一個方法時,當你在用例裏執行這個方法,會在報告裏,表現出這個被裝飾方法;而@step支持嵌套結構,這就意味着,你能夠像搭積木同樣去搭你的步驟,而他們都會一一在報告裏被展現。

下面直接用allure的官方示例做作舉例:

import allure
import pytest

from .steps import imported_step


@allure.step
def passing_step():
    pass


@allure.step
def step_with_nested_steps():
    nested_step()


@allure.step
def nested_step():
    nested_step_with_arguments(1, 'abc')


@allure.step
def nested_step_with_arguments(arg1, arg2):
    pass


def test_with_imported_step():
    passing_step()
    imported_step()


def test_with_nested_steps():
    passing_step()
    step_with_nested_steps()

運行這個case後,報告是這樣的:

 

image

能夠看到,

test_with_nested_steps由passing_step()和step_with_nested_steps()這兩個方法組成;

而step_with_nested_steps()又由nested_step()組成;

nested_step()又由nested_step_with_arguments(1, 'abc')組成;

這樣就像搭積木同樣,組成了測試用例;而在報告裏,也層級分明的標識了步驟的嵌套結構。

這樣,咱們就能夠經過一個又一個@step裝飾的方法,組成測試用例;同時報告裏也會支持層級顯示;從而完成咱們的分層機制。

相關文章
相關標籤/搜索