unittest系統(八)一文搞定unittest重試功能

北漂的雷子發表於2021-08-06

在前面的介紹中,我們對unittest進行了分享介紹,那麼在實際的應用中,因為客觀原因需要對失敗,錯誤的測試用例進行重試,所以呢,現有的unittest的框架無法滿足,那麼我們可以去改造下是否能夠滿足呢。本文帶領大家去剖析如何改寫?

首先呢,我們去試著去找下,我們執行時在BSTestRunner、TextTestRunner或者main,都可以執行用例,那麼我們可以看下這些類或者方法裡面如何實現的。

BSTestRunner呼叫方式如下

 

TextTestRunner的方法是,

 

使用main方法最後的呼叫也是這個函式。詳細的我們可以看下,首先呼叫這個函式,然後在看實際的呼叫.

 

 

最後的呼叫也是這個函式

 

 

 

所以我們就要在裡面的方法去查詢適合我們使用的方法。

在註釋中,我們可以發現在stopTest的方法中可以對其進行改寫。
def stopTest(self, test):        
    """Called when the given test has been run"""        
    self._restoreStdout()        
    self._mirrorOutput = False

  

那麼我們應該如何改寫呢,我們梳理下我們的思路。

  • 1.傳遞重試次數,預設不需要重試
  • 2.在用例執行的錯誤,標記為需要重試
  • 3.在該條用例執行完畢後,我們判斷是否需要重試,重試次數是否滿足
  • 4.如果需要重試,則儲存最新的從測試結果。

那麼我們開始按照上面的思路進行改造。

程式碼如下

import  sys,copy
from io import StringIO as StringIO
TestResult = unittest.TestResult
class MyResult(TestResult):
    def __init__(self, verbosity=1, trynum=0):
        #預設次數是0
        TestResult.__init__(self)
        self.outputBuffer = StringIO()
        self.stdout0 = None
        self.stderr0 = None
        self.success_count = 0
        self.failure_count = 0
        self.error_count = 0
        self.verbosity = verbosity
        self.trynnum = trynum
        self.result = []
        self.trys=0#
        self.istry=False

    def startTest(self, test):
        TestResult.startTest(self, test)
        self.stdout0 = sys.stdout
        self.stderr0 = sys.stderr

    def complete_output(self):
        if self.stdout0:
            sys.stdout = self.stdout0
            sys.stderr = self.stderr0
            self.stdout0 = None
            self.stderr0 = None
        return self.outputBuffer.getvalue()

    def stopTest(self, test):
        #判斷是否要重試
        if self.istry is True :
            #如果執行的次數小於重試的次數 就重試
            if self.trys < self.trynnum :
                #刪除最後一個結果
                reslut = self.result.pop(-1)
                #判斷結果,如果是錯誤就把錯誤的個數減掉
                #如果是失敗,就把失敗的次數減掉
                if reslut[0] == 1:
                    self.failure_count -= 1
                else:
                    self.error_count -= 1
                sys.stderr.write('{}:用例正在重試中。。。' .format(test.id())+ '\n')
                #深copy用例
                test = copy.copy(test)
                #重試次數增加+1
                self.trys += 1
                #測試
                test(self)
            else:
                self.istry=False
                self.trys =0
        self.complete_output()

    def addSuccess(self, test):
        #成功就不要重試
        self.istry = False
        self.success_count += 1
        TestResult.addSuccess(self, test)
        output = self.complete_output()
        self.result.append((0, test, output, ''))
        if self.verbosity > 1:
            sys.stderr.write('ok ')
            sys.stderr.write(str(test))
            sys.stderr.write('\n')
        else:
            sys.stderr.write('.')

    def addError(self, test, err):
        #重試+1,錯誤次數+1
        self.istry = True
        self.error_count += 1
        TestResult.addError(self, test, err)
        _, _exc_str = self.errors[-1]
        output = self.complete_output()
        self.result.append((2, test, output, _exc_str))
        if self.verbosity > 1:
            sys.stderr.write('E  ')
            sys.stderr.write(str(test))
            sys.stderr.write('\n')
        else:
            sys.stderr.write('E')

    def addFailure(self, test, err):
        self.istry = True
        TestResult.startTestRun(self)
        self.failure_count += 1
        TestResult.addFailure(self, test, err)
        _, _exc_str = self.failures[-1]
        output = self.complete_output()
        self.result.append((1, test, output, _exc_str))
        if self.verbosity > 1:
            sys.stderr.write('F  ')
            sys.stderr.write(str(test))
            sys.stderr.write('\n')
        else:
            sys.stderr.write('F')

    def stop(self) -> None:
        pass

這樣改造完畢了,我們可以去試試

if __name__ == "__main__":   
    suitone=suite()   
    rse=MyResult(trynum=3)    
    suitone.run(rse)

執行的結果如下:

image.png

目前改造滿足我們重試用例的需求,改造完畢。

上面只是一個簡單的改造,滿足了對於失敗的測試用例的重試,其實很簡單,我們有了需求,去根據我們的需求去查詢需要改造的程式碼即可,我們直接繼承原來的類,對需要修改的地方 進行修改,已滿足我們的需求。

歡迎關注我的個人公眾號



 

相關文章