自動化測試中對多斷言的思考和實踐

語言: CN / TW / HK

背景

最近筆者在測試一個數據下載專案,測試過程中需要校驗匯出CSV檔案中指標值的準確性。涉及指標數量400+,並且需要關注不同聚合層級、不同時間粒度指標計算的準確性。驗證資料量大,手工驗證效率低、人力成本高,因此通過自動化指令碼的方式來提高測試效率以及方便迴歸驗證。

在實現的過程中,最初採用unittest測試框架中內建的斷言方法,進行資料的比對,實踐發現內建斷言並不能滿足使用要求,進行了一系列的實踐後,最終找到了合適的斷言方案,本篇文章主要介紹了該方案的探索過程。

unittest框架內建的assertEqual斷言

最初使用unittest測試框架中的內建的assertEqual斷言方法,進行實際值與預期值的校驗,assertEqual方法的實現邏輯如下:

1. 如果斷言失敗,則丟擲一個AssertionError,並標識該測試為失敗狀態

2. 如果斷言成功,則標識該測試為成功狀態

指標驗證過程中,一個測試用例中需要包含多個指標斷言,程式碼如下圖所示:

執行結果如下圖所示,一個assertEqual斷言失敗後,丟擲異常,該條用例即被終止,後續斷言不會被繼續執行,從而無法得知後續的斷言執行情況,導致該自動化測試無法一次性反饋所有測試結果,與使用場景要求不符。

一個斷言一個方法

為了解決以上方案中斷言失敗後不再繼續執行其他斷言的問題,將用例進行拆分,將每個指標的斷言放在獨立的方法中,這樣單個指標斷言失敗,不會中斷其他指標的驗證,每個方法中的斷言都會被執行。

實現程式碼如下圖所示:

如下圖中的執行結果可見,雖然test_two方法中的斷言失敗了,但是後續的test_two1方法中的斷言仍可正常執行,並且在全部執行完成後返回異常結果。

此方案雖然解決了斷言失敗不繼續執行的問題,但是需要為每個指標建立獨立的方法去進行結果校驗。在指標數量非常多的情況下,此方案會造成程式碼的大量冗餘,且執行效率較低。

重寫unittest斷言方法

為了從根本上解決斷言失敗後阻斷其他斷言繼續執行的問題,將unittest斷言方法進行了重寫。

實現思路:通過自定義類checkPoint封裝unittest斷言,將assertEqual放入異常捕獲程式碼,斷言失敗時,異常捕獲模組會採集失敗資訊以及失敗次數(記錄在flag中),即使有斷言失敗,也會繼續執行其他斷言。

如下圖所示程式碼,最後獲取用例執行結果時,返回斷言失敗的資訊:

測試用例繼承父類checkPoint,使用封裝的方法,程式碼示例如下圖所示:

使用過程中,當有斷言失敗後,其他斷言也會繼續執行,並在最後返回失敗斷言的資訊,執行結果如下圖所示:

使用pytest框架

除了unittest框架斷言方法外,較為流行的pytest框架也提供了內建的斷言方法,下面讓我們來研究一下,使用pytest框架實現的解決方案。

1. pytest框架中有內建的assert斷言方法

assert斷言方法可以實現結果的校驗,案例程式碼如下:

執行結果如下:

①. 當(x, y)=(1,1)時斷言3失敗;

②. 當(x, y)=(1,0)時斷言1失敗,斷言2和斷言3不執行;

由此可以看出assert方法一旦遇到斷言失敗則停下,無法實現一個方法中多個斷言同時執行的需求。

2. 使用pytest框架pytest-assume外掛

pytest-assume外掛可以解決原生assert斷言方法存在的問題,案例程式碼如下:

執行結果如下:

①. 當(x, y)=(1,1)時斷言3失敗;

②. 當(x, y)=(1,0)時斷言1失敗,斷言2和斷言3繼續執行;

由此可以看出pytest-assume外掛可以實現單個斷言失敗的情況,其他斷言依然會被執行。

3. 上下文管理器with

pytest-assume也可通過上下文管理器with使用,從執行結果中看出,與以上方法中直接使用pytest-assume外掛相比,使用上下文管理器的好處是不用try和finally捕獲異常,更加簡潔有效。

如上圖所示,在使用上下文管理器時需要注意,一個with語句只能跟一個assert語句。如果一個with語句包含多個斷言,當前面的斷言失敗的時候,後面的斷言依然不會執行。

總結

以上是指標校驗指令碼中斷言方案探索的過程,以及最終的解決方案和效果,希望本文能為大家解決類似的問題提供一些思路。

分享給第一個想到的人