日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

Python3的unittest用例按编写顺序执行

發(fā)布時(shí)間:2025/3/20 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python3的unittest用例按编写顺序执行 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

unittest是Python標(biāo)準(zhǔn)庫(kù)自帶的單元測(cè)試框架,是Python版本的JUnit,關(guān)于unittest框架的使用,官方文檔非常詳細(xì),網(wǎng)上也有不少好的教程,這里就不多說(shuō)了。

本文主要分享在使用unittest的過(guò)程中,做的一些擴(kuò)展嘗試。先上一個(gè)例子。

import unittestclass TestLegion(unittest.TestCase): def test_create_legion(self): """創(chuàng)建軍團(tuán) :return: """ def test_bless(self): """ 公會(huì)祈福 :return: """ def test_receive_bless_box(self): """ 領(lǐng)取祈福寶箱 :return: """ def test_quit_legion(self): """退出軍團(tuán) :return: """

這是一個(gè)標(biāo)準(zhǔn)的使用unittest進(jìn)行測(cè)試的例子,寫(xiě)完后心里美滋滋,嗯,就按照這個(gè)順序測(cè)就可以了。結(jié)果一運(yùn)行。

什么鬼。執(zhí)行的順序亂了。第一個(gè)執(zhí)行的測(cè)試用例并不是創(chuàng)建軍團(tuán),而是公會(huì)祈福,此時(shí)玩家還沒(méi)創(chuàng)建軍團(tuán),進(jìn)行公會(huì)祈福的話會(huì)直接報(bào)錯(cuò),導(dǎo)致用例失敗。

到這里有些同學(xué)會(huì)想說(shuō),為什么要讓測(cè)試用例之間有所依賴(lài)呢?

的確,如果完全沒(méi)依賴(lài),測(cè)試用例的執(zhí)行順序是不需要關(guān)注的。但是這樣對(duì)于用例的設(shè)計(jì)和實(shí)現(xiàn),要求就高了許多。而對(duì)游戲來(lái)說(shuō),一個(gè)系統(tǒng)內(nèi)的操作,是有很大的關(guān)聯(lián)性的。以軍團(tuán)為例,軍團(tuán)內(nèi)的每個(gè)操作都有一個(gè)前提,你需要加入一個(gè)軍團(tuán)。所以要實(shí)現(xiàn)用例之間的完全解耦,需要每個(gè)用例開(kāi)始之前,檢測(cè)玩家的軍團(tuán)狀態(tài)。

如果可以控制測(cè)試用例的執(zhí)行順序,按照功能玩法流程一遍走下來(lái),節(jié)省的代碼量是非常可觀的,閱讀測(cè)試用例也會(huì)清晰許多。

如何控制unittest用例執(zhí)行的順序呢?

我們先看看,unittest是怎么樣對(duì)用例進(jìn)行排序的。在loader.py的loadTestsFromTestCase方法里邊,調(diào)用了getTestCaseNames方法來(lái)獲取測(cè)試用例的名稱(chēng)

def getTestCaseNames(self, testCaseClass): """Return a sorted sequence of method names found within testCaseClass """ def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): return attrname.startswith(prefix) and \ callable(getattr(testCaseClass, attrname)) testFnNames = list(filter(isTestMethod, dir(testCaseClass))) if self.sortTestMethodsUsing: testFnNames.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing)) return testFnNames

可以看到,getTestCaseNames方法對(duì)測(cè)試用例的名稱(chēng)進(jìn)行了排序

testFnNames.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing))

看看排序方法

def three_way_cmp(x, y): """Return -1 if x < y, 0 if x == y and 1 if x > y""" return (x > y) - (x < y)

根據(jù)排序規(guī)則,unittest執(zhí)行測(cè)試用例,默認(rèn)是根據(jù)ASCII碼的順序加載測(cè)試用例,數(shù)字與字母的順序?yàn)?#xff1a;0-9,A-Z,a-z。

做個(gè)實(shí)驗(yàn):

import functoolscase_names = ["test_buy_goods", "test_Battle", "test_apply", "test_1_apply"] def three_way_cmp(x, y): """Return -1 if x < y, 0 if x == y and 1 if x > y""" return (x > y) - (x < y) case_names.sort(key=functools.cmp_to_key(three_way_cmp)) print(case_names) output:['test_1_apply', 'test_Battle', 'test_apply', 'test_buy_goods']

基于unittest的機(jī)制,如何控制用例執(zhí)行順序呢?查了一些網(wǎng)上的資料,主要介紹了兩種方式:

方式1,通過(guò)TestSuite類(lèi)的addTest方法,按順序加載測(cè)試用例:

suite = unittest.TestSuite() suite.addTest(TestLegion("test_create_legion")) suite.addTest(TestLegion("test_bless")) suite.addTest(TestLegion("test_receive_bless_box")) suite.addTest(TestLegion("test_quit_legion")) unittest.TextTestRunner(verbosity=3).run(suite) ?

方式2,通過(guò)修改函數(shù)名的方式:

class TestLegion(unittest.TestCase): def test_1_create_legion(self): """創(chuàng)建軍團(tuán) :return: """ def test_2_bless(self): """ 公會(huì)祈福 :return: """ def test_3_receive_bless_box(self): """ 領(lǐng)取祈福寶箱 :return: """ def test_4_quit_legion(self): """退出軍團(tuán) :return: """ ?

看起來(lái)都能滿足需求,但是都不夠好用,繁瑣,代碼不好維護(hù)。

那就造個(gè)輪子吧

于是開(kāi)始了utx這個(gè)小項(xiàng)目,那么如何在不改動(dòng)代碼的情況下,讓測(cè)試用例按照編寫(xiě)的順序依次執(zhí)行呢?

方案就是,在測(cè)試類(lèi)初始化的時(shí)候,將測(cè)試方法按照編寫(xiě)的順序,自動(dòng)依次重命名為“test_1_create_legion”,“test_2_bless”,“test_3_receive_bless_box”等等,從而實(shí)現(xiàn)控制測(cè)試用例的執(zhí)行。

這就需要控制類(lèi)的創(chuàng)建行為,Python提供了一個(gè)非常強(qiáng)力的工具:元類(lèi),在元類(lèi)的__new__方法中,我們可以獲取類(lèi)的全部成員函數(shù),另外基于Python3.6的字典底層重構(gòu)后,字典是有序的了,默認(rèn)順序和添加的順序一致。所以我們拿到的測(cè)試用例,就和編寫(xiě)的順序一致了。

?

?

接下來(lái),就是按照順序,依次改名了,定義一個(gè)全局的total_case_num變量,每次進(jìn)行改名的時(shí)候,total_case_num遞增+1,作為用例的id,加入到用例的名字當(dāng)中。

@staticmethoddef modify_raw_func_name_to_sort_case(raw_func_name, raw_func): case_id = Tool.general_case_id() setattr(raw_func, CASE_ID_FLAG, case_id) if setting.sort_case: func_name = raw_func_name.replace("test_", "test_{:05d}_".format(case_id)) else: func_name = raw_func_name return func_name

接下來(lái)是定義自己的TestCase類(lèi),繼承unittest.TestCase,使用上邊定義的元類(lèi)

class _TestCase(unittest.TestCase, metaclass=Meta): def shortDescription(self): """覆蓋父類(lèi)的方法,獲取函數(shù)的注釋 :return: """ doc = self._testMethodDoc doc = doc and doc.split()[0].strip() or None return doc

最后一步,對(duì)unittest打一個(gè)猴子補(bǔ)丁,將unittest.TestCase替換為自定義的_TestCase

unittest.TestCase = _TestCase

看下運(yùn)行效果,代碼和本文開(kāi)始的例子一樣,只是多了一句utx庫(kù)的導(dǎo)入。

import unittest from utx import *class TestLegion(unittest.TestCase): def test_create_legion(self): """創(chuàng)建軍團(tuán) :return: """ def test_bless(self): """ 公會(huì)祈福 :return: """ def test_receive_bless_box(self): """ 領(lǐng)取祈福寶箱 :return: """ def test_quit_legion(self): """退出軍團(tuán) :return: """

運(yùn)行效果:

?

執(zhí)行順序就和我們的預(yù)期一致了~

基于這一套,開(kāi)始加上其他的一些擴(kuò)展功能,比如

  • 用例自定義標(biāo)簽,可以運(yùn)行指定標(biāo)簽的測(cè)試用例
@unique class Tag(Enum): SMOKE = 1 # 冒煙測(cè)試標(biāo)記,可以重命名,但是不要?jiǎng)h除 FULL = 1000 # 完整測(cè)試標(biāo)記,可以重命名,但是不要?jiǎng)h除 # 以下開(kāi)始為擴(kuò)展標(biāo)簽,自行調(diào)整 SP = 2 class TestLegion(unittest.TestCase): @tag(Tag.SMOKE) def test_create_legion(self): pass @tag(Tag.SP, Tag.FULL) def test_quit_legion(self): """退出軍團(tuán) :return: """ print("吧啦啦啦啦啦啦") assert 1 == 2 from utx import *if __name__ == '__main__': setting.run_case = {Tag.SMOKE} # 只運(yùn)行SMOKE冒煙用例 # setting.run_case = {Tag.FULL} # 運(yùn)行全部測(cè)試用例 # setting.run_case = {Tag.SMOKE, Tag.SP} # 只運(yùn)行標(biāo)記為SMOKE和SP的用例 runner = TestRunner() runner.add_case_dir(r"testcase") runner.run_test(report_title='接口自動(dòng)化測(cè)試報(bào)告')
  • 數(shù)據(jù)驅(qū)動(dòng)
class TestLegion(unittest.TestCase): @data(["gold", 100], ["diamond", 500]) def test_bless(self, bless_type, award): print(bless_type) print(award) @data(10001, 10002, 10003) def test_receive_bless_box(self, box_id): """ 領(lǐng)取祈福寶箱 :return: """ print(box_id) # 默認(rèn)會(huì)解包測(cè)試數(shù)據(jù)來(lái)一一對(duì)應(yīng)函數(shù)參數(shù),可以使用unpack=False,不進(jìn)行解包 class TestBattle(unittest.TestCase): @data({"gold": 1000, "diamond": 100}, {"gold": 2000, "diamond": 200}, unpack=False) def test_get_battle_reward(self, reward): """ 領(lǐng)取戰(zhàn)斗獎(jiǎng)勵(lì) :return: """ print(reward) print("獲得的鉆石數(shù)量是:{}".format(reward['diamond']))
  • 檢測(cè)測(cè)試用例是否編寫(xiě)了說(shuō)明描述
2017-11-03 12:00:19,334 WARNING legion.test_legion.test_bless沒(méi)有用例描述
  • 執(zhí)行測(cè)試用例的時(shí)候,顯示執(zhí)行進(jìn)度
2017-11-03 12:00:19,336 INFO 開(kāi)始進(jìn)行測(cè)試 2017-11-03 12:00:19,436 INFO Start to test legion.test_legion.test_create_legion (1/5) 2017-11-03 12:00:19,536 INFO Start to test legion.test_legion.test_receive_bless_box (2/5) 2017-11-03 12:00:19,637 INFO Start to test legion.test_legion.test_receive_bless_box (3/5) 2017-11-03 12:00:19,737 INFO Start to test legion.test_legion.test_receive_bless_box (4/5) 2017-11-03 12:00:19,837 INFO Start to test legion.test_legion.test_quit_legion (5/5)
  • setting類(lèi)提供多個(gè)設(shè)置選項(xiàng)進(jìn)行配置
class setting:# 只運(yùn)行的用例類(lèi)型 run_case = {Tag.SMOKE} # 開(kāi)啟用例排序 sort_case = True # 每個(gè)用例的執(zhí)行間隔,單位是秒 execute_interval = 0.1 # 開(kāi)啟檢測(cè)用例描述 check_case_doc = True # 顯示完整用例名字(函數(shù)名字+參數(shù)信息) full_case_name = False # 測(cè)試報(bào)告顯示的用例名字最大程度 max_case_name_len = 80 # 執(zhí)行用例的時(shí)候,顯示報(bào)錯(cuò)信息 show_error_traceback = True # 生成ztest風(fēng)格的報(bào)告 create_ztest_style_report = True # 生成bstest風(fēng)格的報(bào)告 create_bstest_style_report = True
  • 集成 ztest 和 BSTestRunner 生成測(cè)試報(bào)告,感謝兩位作者的測(cè)試報(bào)告模版

utx庫(kù)核心源碼不到200行,就不做過(guò)多講解了,直接去Github看吧

作者:煎煎煎餅 鏈接:https://www.jianshu.com/p/d65f97723af7 來(lái)源:簡(jiǎn)書(shū) 簡(jiǎn)書(shū)著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處。

轉(zhuǎn)載于:https://www.cnblogs.com/songzhenhua/p/9690198.html

總結(jié)

以上是生活随笔為你收集整理的Python3的unittest用例按编写顺序执行的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。