背景:公司需要每一個項目組都搭建自己的一套自動化測試框架,編寫測試用例,用於完善公司的測試流程,不限制形式。
核心技術棧:testng+jenkins+maven+dubbo
開發人力:1(80%)
測試人力:1(30%)
耗時:4個月左右
搭建過程:
搭建過程大致分為4個階段:
一階段,
原始需求:由工程效能組的同事提供一個封裝了testng的j框架,給每一個項目組用於編寫自動化測試用例,原本的意圖是由開發配合測試同學編寫代碼,用於完成自動化測試用例。於是,按照這一需求,本人開始編寫代碼,完成測試用例。由於需求簡單,所以只編寫簡單的框架,方便測試同學拷貝,黏貼。起初由本人編寫一些復雜的用例,后續其他的用例,由測試同學仿照我的用例進行編碼,完成剩余的測試用例。
結果表現
1,,在實施的過程中,發現重復邏輯過多
2,工程效能組提供的框架太簡陋
3,最重要的問題,可以說絕大多數的測試同學看不懂代碼,更不要說編碼能力如何,這幾乎為零,導致測試用例無法編寫,壓力全部由開發承擔,且不易於維護。
二階段,
更改需求:由本項目組架構師提出我們內部自行更改需求,具體表現為,讓測試同學不再編寫代碼,通過配置驅動,完成測試用例。此時由於未曾有過這方面的經驗,雖然完成功能,但是效果並不理想
結果表現
1,測試同學能夠開始編寫測試用例
2,配置凌亂且過多
三階段,
優化二階段的成果:具體如下
1,全面優化二階段配置,減少配置文件,減少不必要的配置項
2,完善框架功能,修復bug
3,優化代碼
結果表現
1,用例配置文件減少,配置項減少,測試同學編寫用例速度大幅提升
2,根據測試同學提供的反饋信息,進一步完善功能
3,不斷優化代碼,便於維護
四階段
進一步需求:由於測試用例以配置驅動,但jenkins服務器無法直接上傳配置文件,所以提供web項目輔助測試同學
結果表現:
1,測試同學可自行編寫測試用例,上傳到jenkins服務器
2,測試同學可通過web項目,自行校驗測試用例是否編寫正確,便於修改
下面具體的說一下搭建過程
接口類:
1,調用接口前,需要做數據的植入
2,調用接口前,需要做配置的變更
3,調用接口
4,恢復配置
5,刪除植入的數據
一階段:
第一個階段其實做的事情比較簡單,主要分為2個,第一個是需求分析,第二個是硬編碼
1,需求分析
根據需求,先分析項目組多個系統,發現基本歸於2類,一類是接口,一類是定時任務。接口和定時任務分為多種,需要分類,
接口的校驗分2種,一種是校驗返回結果的,一種是校驗落庫數據的。這個又可以細分,比如一個接口,入參不同,返回結果不同,此為一個接口多個場景等。
定時任務的校驗分2種,一種是校驗落庫數據的,一種是校驗生成文件的。
2,硬編碼
根據需求分析,先編寫接口類測試用例,其中就是硬編碼。
分析:在這個階段,主要是基於testng進行編寫測試用例,基本是硬編碼,由jenkins執行,生成報告。
1,工程效能組同事提供的框架,只支持csv格式的入參和硬編碼入參,非常不好用。
2,連接數據庫使用jdbc,需要自己二次封裝。
3,框架中無常用開發框架如spring,mybatis等
4,由於公司有防火牆及各種客觀硬件原因,導致如果框架中引入spring,會導致jenkins在運行過程中耗時極其嚴重,不得不放棄使用spring等框架
5,由硬編碼寫出大概10個接口的部分場景,積累了經驗
主要問題與難點:
1,框架提供的接口入參不好用
2,編寫代碼過多,不易於維護
解決方案:
1,自行開發json文件入參,xml文件入參等功能
二階段:
根據新的需求,使用配置驅動,后參考的模型為tomcat。
簡單分析一下:
tomcat是我們比較常用的一個web服務器,它是以修改配置文件來完成我們所需要的功能的,但是我們一般簡單使用的話,就是修改一下端口,不過tomcat仍提供大量配置供我們修改用於完成我們的需求,基於這一特性,我們需要制定一套規則
1,配置驅動
2,提供可選配置,如果用戶不配置,那么以默認的配置為主,如果用戶配置,以用戶的配置為主
3,自定義一套規則,以properties文件的形式來驅動
分析:
1,properties文件只能配置簡單的key-value,如果完成復雜的配置,則無能為力
2,規則太繁瑣
主要問題與難點:
1,以配置驅動,一個用例中含有多個接口,多個接口間有參數依賴關系,比如一個CASE含有N個接口,A接口的入參有一個屬性是C接口的入參,B接口的出參有一個屬性是C接口的入參,ABC有順序執行關系,在配置中如何體現
2,如何以配置驅動,完成校驗規則
解決方案:(由於已廢棄,后面詳述)
1,自定義傳參的規則
2,自定義校驗規則
三階段:
此時在二的成果上,進行優化,全面修改規則,目標
1,配置少而精
分析:
1,由於properties文件無法編寫復雜規則,放棄properties文件,
2,二階段的問題,一個CASE中N個接口相互依賴或獨立,如何在配置中體現
3,校驗規則策略問題
解決方案:
1,使用xml文件代替
具體實現
1,自定義xml文件,以CASE的名字命名(可自定義)
2,xml文件格式大致如下,很多配置記不清楚了,基本的如此
<?xml version="1.0" encoding="ISO-8859-1"?> <testcase id="0" name="xxx"> <!--第一組接口--> <group id="0" name="xxx-1"> <!--DUBBO接口全路徑,必須配置--> <service>com.xxx.service</service> <!--DUBBO接口入參全路徑,可不配置,可通過反射獲取,基於一個服務一個方法,一個入參,一個出參,若配置了,以配置的為主--> <request>com.xxx.request</request> <!--DUBBO接口出餐全路徑,可不配置,可通過反射獲取,基於一個服務一個方法,一個入參,一個出參,若配置了,以配置的為主--> <response>com.xxx.response</response> <!--DUBBO接口方法,可不配置,可通過反射獲取,基於一個服務一個方法,一個入參,一個出參,若配置了,以配置的為主--> <method>method</method> <!--DUBBO接口入參json串,必須配置--> <data> { "key":"value", “key1”:"value", } </data> <!--DUBBO接口預計出參,可不配置,可默認就是此配置,此處僅校驗返回碼和message,若配置了,以配置的為主--> <returnDate> { "code":"00", "message":"成功" } </returnDate> <!--DUBBO接口校驗策略,可不配置,默認為此類型校驗策略,若配置了,以配置的為主--> <strategy>default</strategy> </group> <!--第二組接口,以下為最簡配置--> <group id="1" name="xxx-2"> <!--DUBBO接口全路徑,必須配置--> <service>com.xxx.service</service> <!--DUBBO接口入參json串--> <data> { "key":"value" } </data> </group> <!--第三組接口--> <group id="2" name="xxx-3"> <!--DUBBO接口全路徑,必須配置--> <service>com.xxx.service</service> <!--DUBBO接口入參json串,此處自定義規則傳遞參數,group.0代表id=0的group,request代表入參,key代表入參中的屬性名--> <data> { "key":"#{group.0.request.key}", "key1":"#{group.1.response.key}", } </data> </group> </testcase>
以上xml配置,可完成一個CASE有N組接口,每組接口都相互有自己的入參,出參,校驗策略等,相互不受影響,也可以相互依賴,相互傳參,且有序。
2,校驗的配置配置文件參考mybatis的配置文件,如下
<?xml version="1.0" encoding="UTF-8"?> <mapper namespace="com.jfpointscore.dao.UserMapperXml" > <!--校驗接口一般就是2種: 1,校驗接口返回的字段是否正確 2,校驗接口完成請求后,落庫數據是否正確 --> <!--自定義標簽,由測試編寫SQL,自定義校驗dubbo接口返回字段值或落庫數據 id為唯一表示,group與配置中的group相關聯,達到N組接口,N個SQL相互不影響,且有序 --> <sql id="0" group="0"> select a.id as "id" from table a where a.name='張三' </sql> <select id="getUserList" resultMap="BaseResultMap" > SELECT <include refid="Base_Column_List" /> FROM tb_user </select> <select id="getUserById" parameterType="java.lang.Integer" resultMap="BaseResultMap" > SELECT <include refid="Base_Column_List" /> FROM tb_user WHERE id = #{id} </select> <insert id="add" parameterType="com.jfpointscore.entity.core.User" > INSERT INTO tb_user (username,age,ctm) VALUES (#{username}, #{age}, now()) </insert> <update id="update" parameterType="java.util.Map" > UPDATE tb_user SET username = #{user.username},age = #{user.age} WHERE id = #{id} </update> <!--#{id} 代表傳參,由於某些SQL需要DUBBO接口返回的結果作為參數,故此設計,parameterType代表參數類型等,可自定義設計 --> <delete id="delete" parameterType="java.lang.Integer" group="0" > DELETE FROM tb_user WHERE id = #{id} </delete> </mapper>
3,properties文件
properties文件是屬於key-value形式,用於處理一些CASE運行前后需要變更的配置
4,由於在一個CASE運行前后,可能需要做一些數據的植入和刪除動作,故仿照2中的配置,自定義一套數據植入,刪除的sql配置
5,參數傳遞問題,這是由於testng運行決定的,可自行百度。
在參數傳遞問題上的問題在於,以上配置有參數傳遞,那么代碼運行完了,參數到哪里去拿?比如A接口運行完了,B接口運行完了,C接口要拿A接口的出參字段,到哪里去拿?代碼已經跑完了啊?沒有了啊!
我的解決方案是:
1,在CASE運行前,把所有的入參記錄到臨時properties文件中
2,在每一個接口運行后,把出參記錄到臨時properties文件中
3,每一個接口逇入參和出參都用UUID做唯一標識,則可以區分出一個接口完整的入參和出參
4,記錄在臨時文件中不會丟失,但是要記住有文件回收功能,不然文件會越來越大,可參考log日志框架的日志回收功能,以天為單位回收N天前的臨時文件。
四階段
提供web功能進行輔助(不詳述了,就是后台管理系統)
1,需要注意,必須要把之前的邏輯提取出來,保證web的邏輯和jenkins的邏輯是一致的,這個就看代碼寫的好不好了
定時任務類(一般是校驗落庫數據和生成的文件)
分析:
1,觸發定時任務之前,需要數據的植入
2,觸發定時任務之前,需要觸發N個相互依賴或不依賴的接口,觸發接口之前,需要修改接口配置,觸發完成后需要恢復配置
3,觸發定時任務之前,需要修改定時任務配置
4,觸發完成之后,需要恢復配置
5,觸發完成后需要刪除植入的數據
6,觸發完成后需要校驗落庫數據
7,觸發完成后需要校驗生成文件的內容
解決方案:
1,接口部分沿用之前接口的配置,落庫部分沿用之前的校驗配置
2,文件部分,采用遠程登錄linux服務器,到文件成功路徑,使用linux命令搜索文件內容
簡單配置如下:
<?xml version="1.0" encoding="UTF-8"?> <testcase> <!--N個命令,可查詢N個文件,有序,不相關 此處僅是簡化配置 --> <!--command代表linux命令,#{sqlId}代表屬性sqlId,sqlId的值代表sql配置文件中sql的sql的id,相對應,因為存在復雜情況就是文件中的內容從數據庫獲取,再經業務處理生成的,只能通過sql去查詢數據獲取--> <group id="0"> <command>grep '#{sqlId}' /xx/xx/xxxx.txt</command> <sqlId>0</sqlId> </group> <!--簡單命令--> <command id="1" group="1"> grep 'xxx' /xx/xx/xxxx.txt </command> <command id="2" group="2"> grep 'xxx' /xx/xx/xxxx.txt </command> </testcase>
當然,其中還有很多復雜配置,但是不記得了
基於這些配置,測試同學只需要按照規則,配置好配置,jenkins會自動運行代碼,解析配置,進行校驗,從而完成測試。