背景是這樣的:
自己寫了一套接口自動化的框架,其中使用unittest + ddt + excel作為數據驅動模式的應用,使用HtmlTetstRunner來生成測試用例。
一切看起來很完美。
但是,發現測試報告中,測試用例名稱都是:test_api_index.index表示用例的編號,從1開始,遞增。比如:test_api_01、test_api_02......test_api_0N
希望能在不同的用例名稱當中,顯示相應的接口用例名字。比如登陸接口的成功登陸用例:測試報告中用例名稱顯示為test_login_success。密碼錯誤的用例名稱為:test_login_wrongPasswd
這樣,我直接從報告中就可以知道是哪個接口的哪個用例失敗了,一目了然。
於是,就開始琢磨這事兒了。。。
======================================背景分割線==================================
一琢磨就琢磨到ddt源碼上去了。心中有一個疑惑:
1、為什么我的測試用例名稱是這樣的??
查看了ddt源碼之后,發現有個函數是用來生成測試用例名字的。這個函數叫:mk_test_name
它是如何來生成測試用例名字的呢?
它接受兩個參數:name 和 value.
name:為單元測試中,測試用例的名字。即test_api.
value:為測試數據。ddt是處理一組測試數據。而這個value就是這一組數據中的每一個測試數據。
對value的值是有限制的:要么就是單值變量,要么就是元組或者列表並且要求元組和列表中的數據都是單值變量。如("name","port") 、["name","port"]
如果傳進來的測試數據,不符合value的要求,那么測試用例名字為:name_index。
如果傳進來的測試數據,符合value的要求,那么測試用例名字為:name_index_value。如果value為列表或者元組,那么將列表/元組的每個數據依次追加在末尾。
比如傳進來的name值為test_login,value值為["name","port"]。那最終的測試用例名字是:test_login_01_name_port。
如果傳進來的name值為test_login,value值為{"name":"login","port":2204},那最終的測試用例名字為:test_login_01。因為它不支持對字典類型的數據處理。
很不巧,我的接口自動化框架中,ddt處理的數據是一列表:列表當中每個數據都為字典。ddt一遍歷整個列表,那傳給value的值剛好是字典。。
so。。。我得到的測試用例名稱就是:test_api_01,test_api_02,test_api_03..........test_api_0N
ddt源碼如下(紅色粗體部分標識):
1 def mk_test_name(name, value, index=0): 2 """ 3 Generate a new name for a test case. 4 5 It will take the original test name and append an ordinal index and a 6 string representation of the value, and convert the result into a valid 7 python identifier by replacing extraneous characters with ``_``. 8 9 We avoid doing str(value) if dealing with non-trivial values. 10 The problem is possible different names with different runs, e.g. 11 different order of dictionary keys (see PYTHONHASHSEED) or dealing 12 with mock objects. 13 Trivial scalar values are passed as is. 14 15 A "trivial" value is a plain scalar, or a tuple or list consisting 16 only of trivial values. 17 """ 18 19 # Add zeros before index to keep order 20 index = "{0:0{1}}".format(index + 1, index_len) 21 if not is_trivial(value): #如果不符合value的要求,則直接返回用例名稱_下標作為最終測試用例名字。 22 return "{0}_{1}".format(name, index) 23 try: 24 value = str(value) 25 except UnicodeEncodeError: 26 # fallback for python2 27 value = value.encode('ascii', 'backslashreplace') 28 test_name = "{0}_{1}_{2}".format(name, index, value) 29 return re.sub(r'\W|^(?=\d)', '_', test_name)
2、修改ddt源碼,顯示測試用例名字
為了讓我的測試報告,呈現的更好。那就改改ddt源碼,讓它能夠適應我的框架。
考慮兩個問題:
1、不同接口的測試用例名字如何來??
2、如何讓ddt支持對字典的處理??
解決方法:
第一個問題:每一個測試用例主動提供一個用例名字,說明你是什么接口的什么場景用例。比如:接口名_場景名。login_success、login_noPasswd、login_wrongPasswd等。
在我的框架當中,每一個測試用例是一個字典。那么我就在字典中添加一個鍵值對,case_name=用例名稱
第二個問題:在ddt中添加對字典的處理,如果字典中有case_name字段,則將字典中鍵名為case_name的值作為測試用例名稱中的value值。
修改后的ddt源碼為(紅色粗體部分為修改的內容):
1 def mk_test_name(name, value, index=0): 2 3 print("-------first value------------") 4 print(value) 5 # Add zeros before index to keep order 6 index = "{0:0{1}}".format(index + 1, index_len) 7 #添加了對字典數據的處理。 8 if not is_trivial(value) and type(value) is not dict: 9 return "{0}_{1}".format(name, index) 10 #如果數據是字典,則獲取字典當中的api_name對應的值,加到測試用例名稱中。 11 if type(value) is dict: 12 try: 13 value = value["case_name"] #case_name作為value值 14 except: 15 return "{0}_{1}".format(name, index) 16 try: 17 value = str(value) 18 except UnicodeEncodeError: 19 # fallback for python2 20 value = value.encode('ascii', 'backslashreplace') 21 test_name = "{0}_{1}_{2}".format(name, index, value) 22 23 return re.sub(r'\W|^(?=\d)', '_', test_name)
修改完成之后,再次運行接口測試,就可以在測試報告當中看到對應的用例名字啦。。