接口自動化測試流程和相關準備工作

第一步: 拿到需求文檔、UI交互圖(原型圖)、數據庫表設計文檔、接口文檔

1問:爲什麼要拿到這些文檔資料呢?

1答:

①.《需求文檔》,明確定義了:各個表單字段的限制條件;相關場景邏輯校驗;

②.《UI交互圖》,明確定義了:各單頁面需展示的數據;頁面之間的交互;

③.《數據表設計文檔》,結合UI圖和需求文檔,明確定義了:表字段規則、表N多N關係(一對一、一對多、多對多);

④.《接口文檔》,結合需求文檔和UI和數據表,明確定義了:接口名,各個入參值,各個返回值,和其他相關信息;

2細節:

①.大多數公司,針對這四類文檔資料都整理的不規範,或者沒能及時更新;

②.這會導致接口測試用例的編寫沒有一個絕對可靠的需求來源

③.因爲,接口測試用例本質是針對各個表字段的校驗;

④.所以需求文檔裏對各個表單字段的限制條件,產品人員務必都要寫清楚,不要遺漏限制條件;

⑤.而接口文檔裏針對各個用例場景的返回值,文檔裏務必都要及時填寫和更新;

⑥.針對接口文檔返回值的字段:比如code=0表示登錄成功,code=1表示密碼錯誤;code=2表示無網絡;code=3表示賬號錯誤,等等類似code值有不同含義;

3注意:

①.所以,在寫接口測試用例之前,務必要先覈對需求文檔和接口文檔,以最正確的需求文檔和接口文檔,來編寫接口用例,才能得到最正確的結果;

②.先實現單接口解耦;後續按照業務場景組合多個接口;

 

 

第二步: 拿到個人編寫的接口用例模板,針對特定單接口編寫接口用例

 

1重點:要及時更新接口用例模板.xlsx,保證用例模板的準確性;

2假設有一個後臺系統banner廣告位子模塊,以特定單接口-createBanner-新增banner,來講解編寫單接口的接口用例的操作流程:

1)新建一個xlsx後綴的excel文檔,excel名改爲:banner.xlsx

2)打開banner.xlsx,第一個sheet頁名稱改爲:創建banner

3)打開接口用例模板.xlsx,把名稱爲【接口測試demo】的sheet頁裏的所有內容複製到banner.xlsx的名稱爲【創建banner】的空sheet頁;

4)在名稱爲【創建banner】的sheet頁裏,做如下步驟的操作:

4-1)針對第一行各單元格數據(第一行各單元格是用來填寫相關參數名和用於標識的參數名):

按照實際需求來靈活配置:操作入參名所在的單元格;操作返回參數名所在的單元格;

入參名都用紅色字體表示;返回參數名都用綠色字體表示;

比如:修改某個入參名,刪除多餘的一個入參名所在的一個列,新增一個列來填寫一個新的入參名;

比如:修改某個返回參數名,刪除多餘的一個返回參數名所在的一個列,新增一個列來填寫一個新的返回參數名;

②跟入參名跟返回參數名所在的單元格無關的單元格,都保持原位置和原單元格名稱即可。

當然也支持任意移動位置和更改單元格名,但不建議更改單元格名因爲更改了單元格名後代碼也要跟着變動)

 

4-2)針對第二行各單元格數據(第二行各單元格是用來填寫默認值):

①單元格【驗證字段】的值:不填,爲空;

②單元格【接口地址】的默認值值是接口相對路徑,結合實際情況比如更改爲:/api/b.banner/creBanner,用於拼接該接口請求的絕對路徑;

③單元格【請求方式】的默認值值是請求方式,結合實際情況比如更改爲:post;

④單元格【編號】的值:不填,爲空;

⑤單元格【返回值和斷言結果的所在行下標】的值:不填,爲空;

⑥單元格【用例類型】的值:不填,爲空;

⑦單元格【用例目的】的值:不填,爲空;

⑧單元格【用例名】的值:不填,爲空;

⑨單元格【返回值】的值:不填,爲空;

⑩單元格【斷言結果】的值:不填,爲空;

細節1:如果入參名所在的單元格和返回參數名所在的單元格,單元格值可以重複且出現頻率高,那就可以填寫默認值

細節2:如果入參名所在的單元格和返回參數名所在的單元格,單元格值不可以重複只能是唯一值,那就單元格值爲空

 

4-3)針對第三行及大於第三行的各單元格數據(用於填寫具體值):

結合接口用例模板.xlsx的名爲【接口測試用例模板】sheet頁稱爲A,在banner.xlsx的名爲【創建banner】sheet頁稱爲B,進行靈活填寫;

操作步驟:

①針對某個接口字段,複製A的三列數據【用例類型】【用例目的】【示範的用例名】,複製給B的三列數據【用例類型】【用例目的】【用例名】;

②然後刪除不需要的用例名對應的行數據;

③更改各條剩下的用例名,比如更改字段名和相關數字等數據;(基本99%都要替換掉從模板複製過來的數據);

④B的這列數據【接口地址】,務必都填寫DF;

⑤B的這列數據【請求方式】,務必都填寫DF;

⑥B的這列數據【編號】,務必都填寫文本形式的數字且數字遞增,值從01開始(文本形式的數字可以再excel裏設置);

⑦B的這列數據【返回值和斷言結果的所在行下標】,務必都填寫數字且數字遞增,值從2開始;

⑧B的這列數據【驗證字段】,靈活按照實際入參名來填寫;

⑨B的兩列數據【code】【data】都務必結合接口文檔和需求文檔,填寫正確的值;(若哪些值覺得不合理,後期可以讓產品或開發人員進行修改);

⑩B的兩列數據【code】【msg】都務必結合接口文檔和需求文檔,填寫正確的值;(若哪些值覺得不合理,後期可以讓產品或開發人員進行修改);

細節1:DF表示默認值,取值於第二行各自的單元格值(在腳本里有做相關轉化和校驗);

細節2:&$,表示一個變量,由腳本內部賦值。比如: variable = {"${count}": 666} ;

細節3:B的兩列數據【返回值】【斷言結果】都默認不填寫,這兩列數據都是由相關腳本返回的值;

細節4: 相關顏色的標註,可結合實際來靈活填寫;

細節5: 列數據【data】和列數據【msg】不可能同時有值;

細節6:待補充列表字段【預期值】,把【code】+【data】&【code】+【msg】這樣組合爲一個dict,回傳寫入【banner(包含接口返回值和斷言結果).xlsx】;

 

 

第三步: 結合項目框架,做相關流程的腳本操作

1)第一,執行必須操作的步驟(按項目二級目錄的排序順序來執行)

1. 在二級模塊名【/data】內:編寫腳本d_add_banner.py; (在子類D_add_banner的父類屬性variable可結合banner.xlsx內的接口用例賦值情況,來重寫該variable屬性值;)

2. 在二級模塊名【/excel】內:存放banner.xlsx;

3.在二級模塊名【/expectedResult】內:編寫腳本e_add_banner ; (第一次編寫子類E_add_banner時,直接繼承且不重寫任何一個父類方法;調試期間,可按照實際重寫父類相關方法;);

4. 在二級模塊名【/model】內:編寫腳本m_add_banner.py; (第一次編寫子類M_add_banner.py時,直接繼承且不重寫任何一個父類方法;調試期間,可按照實際重寫父類相關方法;)

5. 在二級模塊名【/optimize】內:編寫腳本o_add_banner.py; (第一次編寫子類O_add_banner.py時,直接繼承且不重寫父類的sleep方法;調試期間,可按照實際重寫父類的sleep方法;)

6. 在二級模塊名【/validate】內:編寫腳本v_add_banner.py;(第一次編寫子類V_add_banner.py時,直接繼承且不重寫父類的compareResult方法;調試期間,可按照實際重寫父類的compareResult方法;)

7. 在二級模塊名【/writeCellValue】內:編寫腳本w_add_banner.py;

 

細節:各步驟對應的類都相對解耦,數據源基本都來自同個上游接口--d_add_banner.py內的子類D_add_banner所調用的父類方法excel_data()的返回值;

 

2)第二,再執行非必須操作的步驟(按項目二級目錄的排序順序來執行)

1. 在二級模塊名【/fileAttribute】內:編寫腳本f_add_banner.py;

2. 在二級模塊名【/public】內:存放圖片視頻等相關測試數據;

 

3)第三,針對單接口createBanner,調試接口請求

1. 在二級模塊名【/controller】內:編寫腳本c_add_banner.py; (第一次編寫C_add_banner.py時,務必對某個特定的父類方法進行重寫,比如:父類方法add,父類方法update;)

細節1: 相關入參值都採取參數化;

細節2:在【if __name__ == '__main__':】下方區域,進行單元測試的調試;

細節3:用於調試的數據源data,可以在【d_add_banner.py內的子類D_add_banner所調用的父類方法excel_data()的返回值】這邊獲取,獲取符合要求的其中一條數據來當做數據源;

 

4)第四,針對單接口createBanner,結合ddt,遍歷執行所有的接口測試用例

1. 在二級模塊名【/testcase】內:編寫腳本test_001_add_banner_testcase.py;

細節1:可直接複製其餘現成的腳本,用ctrl+R快捷鍵統一替換相關關鍵字;

細節2:針對不同接口,腳本需增加/減少特定的代碼;(比如【修改】接口可能比【新增接口】需要多調用sleep方法,防止程序執行過快導致接口請求異常返回報錯信息)

細節3:成功執行該腳本後,會在二級模塊名【/excel】裏生成對應的【banner(包含接口返回值和斷言結果).xlsx】,會包含每條接口用例的返回值和斷言結果;

 

 

5)第五,覈對生成的數據

1. 查看【banner(包含接口返回值和斷言結果).xlsx-【創建banner】sheet頁的 返回值和斷言結果】,大概看一下返回值的數據是否正確;如果有錯誤的返回值,則繼續排查和優化相關腳本;

 

6)第六,執行單一入口函數

 

步驟:

1.配置根目錄run.py相關參數信息;

2.執行run.py

3.生成html格式的測試報告;並,發送相關報告至指定郵箱;

後期拓展:

1.部署線上jenkins服務,部署本地/線上python環境,部署本地/線上wamp環境,CI持續集成;

2.熟悉相關linux命令;優化相關腳本邏輯;

3.部署線上禪道服務,實現主要功能:實時寫入bug&獲取bug清單&更改bug狀態,下載最新包含符合篩選條件的bug的excel文檔;

 

 

 python相關核心腳本如下:

 1 # coding:utf-8
 2 '''
 3 @file: test_002_update_banner_testcase.py
 4 @author: jingsheng hong
 5 @ide: PyCharm
 6 @createTime: 2019年07月29日  10點21分
 7 @contactInformation: [email protected]
 8 '''
 9 
10 
11 import unittest
12 import ddt
13 from data.b.banner.d_update_banner              import D_update_banner
14 from controller.b.banner.c_update_banner        import C_update_Banner
15 from expectedResult.b.banner.e_update_banner    import E_update_banner
16 from validate.b.banner.v_update_banner          import V_update_banner
17 from optimize.b.banner.o_update_banner          import O_update_banner
18 from writeCellValue.b.banner.w_update_banner    import W_update_banner
19 
20 excel_data = D_update_banner().excel_data()
21 
22 @ddt.ddt
23 class Test_update_banner(unittest.TestCase):
24     '''【更新banner】接口的接口測試用例集合'''
25 
26     def setUp(self):
27         pass
28 
29     def tearDown(self):
30         pass
31 
32     @ddt.data(*excel_data)
33     def test_update_banner(self,data):
34         O_update_banner(data).sleep()
35         O_update_banner(data).printAllParamsLog()
36         expectResult    =  E_update_banner(data).update()
37         actualResult    =  C_update_Banner(data).update()
38         W_update_banner(data).writeReturnValue(actualResult)
39         O_update_banner(data).printLog(expectResult,actualResult)
40         compareResult   =  V_update_banner(expectResult,actualResult).compareResult()
41         assertResult    =  V_update_banner(expectResult,actualResult).assertResult()
42         W_update_banner(data).writeAssertResult(assertResult)
43         self.assertTrue(compareResult)
44 
45 if __name__ =="__main__":
46     unittest.main()

 

 

php相關控制層腳本如下:

  1 <?php
  2 /**
  3  * Created by PhpStorm.
  4  * User: Administrator
  5  * Date: 2019/03/25
  6  * Time: 19:02
  7  */
  8 
  9 namespace app\api\controller\b;
 10 
 11 use app\api\controller\ApiCommon;
 12 use app\api\controller\utils\File;
 13 use app\api\model\ModelBanner;
 14 use app\api\validate\V_Banner;
 15 use think\Db;
 16 use think\Response;
 17 
 18 class Banner  extends ApiCommon
 19 {
 20 
 21     /**  後臺查詢banner列表(可傳id獲取單個banner信息)
 22      * @return \think\Response
 23      */
 24     public function showBannerA(){
 25         $id = input('param.id');
 26         $page = input('param.page');
 27         $last = input('param.last');
 28         //實例化content,查詢all
 29         $mBanner = new ModelBanner();
 30         $list = $mBanner->showBannerA($id,$page,$last);
 31         $count = $mBanner->countBanner();
 32         list_upload_image_path_format($list,'image');
 33         if ($list){
 34             $data = [
 35                 'code'=>0,
 36                 'count'=>$count==0?'':$count,
 37                 'data'=>$list,
 38             ];
 39             return response($data,0,array(),'json');
 40         }else{
 41             return api_list_not_more();
 42         }
 43     }
 44     //Banner排序接口
 45     public function sortBanner(){
 46         //獲取到的id和sort值
 47         $param = input('param.');
 48         if (empty($param)){
 49             return api_param_error();
 50         }
 51         $all=[];
 52         for ($i = 0;$i<count($param['id']);$i++){
 53             //驗證參數
 54             $validate = new V_Banner();
 55             if (!$validate->scene('sort')->check(['sort'=>$param['sort'][$i]])) {
 56                 return api_param_error($validate->getError());
 57             }
 58             $info['id']=$param['id'][$i];
 59             $info['sort']=$param['sort'][$i];
 60             $all[] = $info;
 61         }
 62         $banner = new ModelBanner();
 63         $res = $banner->saveAll($all);
 64         if ($res){
 65             return api_success('操作成功');
 66         }else{
 67             return api_error();
 68         }
 69     }
 70 
 71     /**  刪除banner(傳id刪除單個banner或傳數組批量刪除)
 72      * @return \think\Response
 73      */
 74     public function delBanner(){
 75         $id = input('param.id');
 76         $mBanner = new ModelBanner();
 77         $banner =$mBanner->delBanner($id);
 78         if ($banner){
 79             return api_success('成功刪除');
 80         }else{
 81             return api_error();
 82         }
 83     }
 84     /**  創建banner
 85      * @return Response
 86      */
 87     public function creBanner(){
 88         //獲取內容信息    id title img_path status  type
 89         $info = input('param.');
 90         //驗證參數
 91         $validate =  new V_Banner();
 92         if (!$validate->scene('create')->check($info)) {
 93             return api_param_error($validate->getError());
 94         }
 95         if (strpos($info['sort'],'.')){
 96             return api_error('排序只能是整數');
 97         }
 98         $banner = new ModelBanner();
 99         $sort = $banner->where('sort',$info['sort'])->find();
100         if ($sort){
101             return api_error('此排序數字已經存在');
102         }
103         $file = new File();
104         $files = $file->upload('Banner','image',true);
105         //判斷是否上傳文件
106         if ($files instanceof Response) {
107             return api_error('沒有上傳圖片');
108         }
109         //檢查是否上傳成功
110         if ($files[0]['is_success']) {
111             // 啓動事務
112             Db::startTrans();
113             try {
114                 $info['image'] = $files[0]['file_path'];
115 
116                 $res = $banner->save($info);
117                 if ($res){
118                     // 提交事務
119                     Db::commit();
120                     return api_success('創建成功!');
121                 }
122             } catch (\Exception $e) {
123                 // 回滾事務
124                 Db::rollback();
125                 return api_success('創建失敗!');
126             }
127         }else{
128             return api_error($files[0]['error_msg']);
129         }
130 
131     }
132     /** 修改banner
133      * @return \think\Response
134      */
135     public function upBanner(){
136 
137         //獲取內容信息    id title img_path status  type
138         $info = input('param.');
139         //驗證參數
140         $validate =  new V_Banner();
141         if (!$validate->scene('update')->check(input('param.'))) {
142             return api_param_error($validate->getError());
143         }
144         if (strpos($info['sort'],'.')){
145             return api_error('排序只能是整數');
146         }
147         $banner = new ModelBanner();
148         $sort = $banner->where('sort',$info['sort'])->find();
149         if ($sort){
150             if (!$banner->where('sort',$info['sort'])->find($info['id'])){
151                 return api_error('此排序數字已經存在');
152             }
153         }
154         $file = new File();
155         $files = $file->upload('Banner','image',true);
156 
157         //判斷是否上傳文件
158         if (!$files instanceof Response) {
159             //判斷是否符合大小和格式
160             if (!$files[0]['is_success']) {
161                 return api_error($files[0]['error_msg']);
162             }
163             $info['image'] = $files[0]['file_path'];
164         }
165         // 啓動事務
166         Db::startTrans();
167         try {
168             $mBanner = new ModelBanner();
169             $res = $mBanner->save($info,['id'=>$info['id']]);
170             if ($res){
171                 // 提交事務
172                 Db::commit();
173                 return api_success('修改成功!');
174             }
175         } catch (\Exception $e) {
176             // 回滾事務
177             Db::rollback();
178             return api_error('修改失敗!');
179         }
180     }
181 
182 
183 
184     /**  banner上下線功能
185      * @return Response
186      */
187     public function togStatus(){
188         $id = input('param.id');
189         if (empty($id)){
190             return api_param_error();
191         }
192         $mBanner = new ModelBanner();
193         $result=$mBanner->togStatus($id);
194         if($result){
195             return api_success("操作成功!");
196         }else{
197             return api_error();
198         }
199 
200     }
201 
202     /**  測試
203      * @return array|false|\PDOStatement|string|\think\Model
204      */
205     function f(){
206         $id = input('param.');
207         $banner = new ModelBanner();
208         $item = $banner->find($id);
209         return $item;
210     }
211 
212     public function image(){
213 //        $arr = input('param.');
214 //        dump($arr);
215 //        return $arr;
216         return input('param.');
217         return $_POST['title'];
218         return $_FILES;
219         $files = request()->file('file');
220         return $files;
221     }
222 
223 }

 

 

 

待更新 ...

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章