1. 程式人生 > >自動化測試關鍵字驅動的原理及實現

自動化測試關鍵字驅動的原理及實現

轉載地址:http://www.cnblogs.com/zhangfei/p/5330994.html

自動化測試現在越來越趨向於平臺化,平臺化是致力於協同工作,提高效率,讓更多人蔘與自動化的一個過程,在我看來,平臺化中,有一個更為關鍵點,就是關鍵字驅動,只有把自動化測試的程式碼轉換成為大家更容易懂的自然語言,才能讓更多不懂程式碼的人加入進去,才能達到平臺化的目的。今天我們就來談談自動化測試中關鍵字驅動的原理及實現方式。

       先來看一個例子,老師對著同學們說了一句:去把桌子從A地點搬到B地點。當老師發出這個命令後,發現沒有人動,因為沒有明確的物件,不知道這個命令是對誰發出的,於是老師再說了一句:張三,去把桌子從A地點搬到B地點。這時候,有了明確的物件--張三,有了命令的主體--搬桌子從A到B。所以這句” 張三,去把桌子從A地點搬到B地點”中就有兩個關鍵字:張三、把桌子從A地點搬到B地點。當這兩個關鍵字缺少任何一個,這件事就不可能完成。所以,我們可以把這個場景理解為關鍵字驅動,假如我們把上面這句話轉換為程式碼:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class MoveDesk { private Person zhangsan; public void setZhangsan(Person zhangsan) { this.zhangsan = zhangsan; } public void moveDeskFromA2B(){ zhangsan.getTheCommandFromTeacher(); zhangsan.findTheDeskAtA(); zhangsan.moveDeskToB();
zhangsan.notifyTeacherHadFinished(); } public static void main(String[] args) { MoveDesk md = new MoveDesk(); md.setZhangsan("張三"); md.moveDeskFromA2B(); } }

上面的程式碼當然是虛擬碼,但從中可以看出,其為了達到一個目的,流程都是一樣的,那兩個關鍵字在main方法中體現為:張三對應md.setZhangsan("張三"),”把桌子從A地點搬到B地點”對應md.moveDeskFromA2B()。由此我們可以這樣理解一下:每一個關鍵字對應一個具體的方法。所以,總結一下關鍵字驅動的實現特點:

1. 每一個關鍵字對應的方法(以下稱為關鍵方法)必須能夠隨時被呼叫,這就像老師對張三發出的命令張三必須去執行一樣。在JAVA裡面為了達到這個關鍵方法隨時能被呼叫,其類物件必須事先就被new好,所以要有一個物件池,這個物件池就像一個班級,有很多個學生可以供老師發出命令並去執行。

2. 關鍵字必須與關鍵方法進行關聯,就像老師讓張三搬桌子,而張三跑去買了一包煙,這就不對了,所以,必須要有一個關鍵字與關鍵方法的對映表。

3. 得有一個關鍵字的解析方式,比如上面那條命令中,我們要能夠得出張三、把桌子從A地點搬到B地點這兩個關鍵字,要是不能得出關鍵字,關鍵方法就會少執行,就如上面的虛擬碼中,如果去掉md.setZhangsan("張三")這一句,顯然就會報空指標異常了。

4. 上面這三條具備後,就是執行了,老師發出的命令,張三要能夠執行,當然,要是張三是個刺頭就另說了。JAVA程式碼能夠交給JVM去執行,但轉換成為關鍵字後,JVM就不認識這些關鍵字了,所以,我們也必須要有一個健壯的執行引擎,讓“張三,去把桌子從A地點搬到B地點”這一句話能夠被執行成功。

綜上所述,只要我們把上面的四條通過程式碼來實現,一個簡單的關鍵字框架雛形就出來了,接下來我們一條條的實現。

1.物件池:

1 2 3 4 5 6 7 8 public class RegisterCenter { public static Map<String, Object> OBJ_POOLS = new HashMap<String, Object>(); static{ OBJ_POOLS.put(MoveDesk.class.getName(), new MoveDesk()); } }

將所有含有關鍵方法的類都初始化一遍,然後放到OBJ_POOLS這個物件裡,方面後面直接呼叫關鍵方法。(請大家試著用註解去實現,會更炫)

2.對映表:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class KeywordReflect { public static Map<String, Map<String, String>> KEYWORD_POOLS = new HashMap<String, Map<String, String>>(); static{ KEYWORD_POOLS.put("張三", KeywordReflect.methodInfo(MoveDesk.class.getName(), "setZhangsan")); KEYWORD_POOLS.put("把桌子從A地點搬到B地點", KeywordReflect.methodInfo(MoveDesk.class.getName(), "moveDeskFromA2B")); } public static Map<String, String> methodInfo(String className, String methodName){ Map<String, String> methodInfo = new HashMap<String, String>(); methodInfo.put("class", className); methodInfo.put("method", methodName); return methodInfo; } }

說明:上面的KEYWORD_POOLS物件的資料結構是MAP裡面套了一個MAP,這是因為要明確類物件,因為不同的類裡可能有相同名稱的方法,所以,為了避免混亂,必須標註好一個方法的類與方法名,這樣才能建立好一一對應的對映表。(同樣可以用註解來實現)

3.解析關鍵字

為了能夠解析出關鍵字,我們得把” 張三,去把桌子從A地點搬到B地點”這句話的關鍵字給標註出來,改造一下”${張三},去${把桌子從A地點搬到B地點}”,這樣就把關鍵字給明確的標註出來了,雖然從直觀感受上差了那麼一點點,但卻是關鍵字驅動中很重要的一部分。接下來的問題轉變成為了對一段字串中${}的解析了:

正則類:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class RegExp { public boolean match(String reg, String str) { return Pattern.matches(reg, str); } public List<String> find(String reg, String str) { Matcher matcher = Pattern.compile(reg).matcher(str); List<String> list = new ArrayList<String>(); while (matcher.find()) { list.add(matcher.group()); } return list; } }

 獲取關鍵字類:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ParseKeyword { public List<String> getKeywords(String p){ String reg = "(?<=(?<!\\\\)\\$\\{)(.*?)(?=(?<!\\\\)\\})";     RegExp re = new RegExp(); List<String> list = re.find(reg, p); return list; } public static void main(String[] args) { ParseKeyword p = new ParseKeyword(); System.out.println(p.getKeywords("a${a}a")); System.out.println(p.getKeywords("a\\${a}a")); System.out.println(p.getKeywords("a${a\\}a")); System.out.println(p.getKeywords("a${a\\}a}a")); System.out.println(p.getKeywords("a${a}a${")); System.out.println(p.getKeywords("a${ab}a${a}")); } }

說明:裡面用到了正則預查模式,正則預查模式是正則中的一種相對高階的用法,掌握這個後,你的正則就會上一個臺階。

4. 執行引擎:

執行引擎先要找到需要執行的語句,所以,首先應該把老師發的那個命令給讀取出來,這個命令可以存放在任何格式的檔案裡,只要能被讀出來即可,在這裡我們儲存在command.txt裡:

讀取這個命令:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Executor { public List<String> readTxtFile(String filePath) { List<String> list = new ArrayList<String>(); try { String encoding = "UTF8"; File file = new File(filePath); if (file.isFile() && file.exists()) { InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding); BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { list.add(lineTxt); } read.close(); bufferedReader.close(); } else { System.out.println("找不到指定的檔案"); } } catch (Exception e) { System.out.println("讀取檔案內容出錯"); e.printStackTrace(); } return list; } public static void main(String[] args) { Executor e = new Executor(); System.out.println(e.readTxtFile("src/command.txt")); } }

讀取之後,流程就是:獲取關鍵字->獲取關鍵方法->執行關鍵方法.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public class Executor { private ParseKeyword pk = new ParseKeyword(); public List<String> readTxtFile(String filePath) { List<String> list = new ArrayList<String>(); try { String encoding = "UTF8"; File file = new File(filePath); if (file.isFile() && file.exists()) { InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding); BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { list.add(lineTxt); } read.close(); bufferedReader.close(); } else { System.out.println("找不到指定的檔案"); } } catch (Exception e) { System.out.println("讀取檔案內容出錯"); e.printStackTrace(); } return list; } public void executor(){ List<String> commands = this.readTxtFile("src/command.txt"); for (String command : commands) { List<String> keywords = pk.getKeywords(command); for (String keyword : keywords) { this.invoke(keyword); } } } public void invoke(String keyword){ Map<String, String> keyMethod = KeywordReflect.KEYWORD_POOLS.get(keyword); String className = keyMethod.get("class"); String methodName = keyMethod.get("method"); Object obj = RegisterCenter.OBJ_POOLS.get(className); Method method = this.getMethod(methodName, obj); try { method.invoke(obj); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } private Method getMethod(String methodName, Object obj) { try { Method[] methods = obj.getClass().getMethods(); for (Method m : methods) { if (m.getName().equals(methodName)) { return m; } } } catch (SecurityException e) { return null; } return null; } public static void main(String[] args) { Executor e = new Executor(); e.executor(); } }

為了大家能夠看到執行結果,把MoveDesk類給改改:

1 2 3 4 5 6 7 8 9 10 11 public class MoveDesk { public void setZhangsan() { System.out.println("this is zhangsan"); } public void moveDeskFromA2B(){ System.out.println("this is test!"); } }

這樣執行之後,就能看到這兩個關鍵方法體被執行了!執行引擎中最關鍵的就是利用了JAVA的反射來執行方法!

以上的程式碼經過測試執行通過!

由此一個最最簡單的關鍵字驅動架子就搭建完成了,還有如下的一些點需要大家自行去完成:關鍵方法引數處理,關鍵方法返回值處理,異常處理,結合資料驅動,結合測試框架(TESTNG/JUNIT)等。也有很大的優化空間留給大家自行發揮去吧!

點亮測試人生!QQ:408129370

相關推薦

自動化測試關鍵字驅動原理實現

轉載地址:http://www.cnblogs.com/zhangfei/p/5330994.html 自動化測試現在越來越趨向於平臺化,平臺化是致力於協同工作,提高效率,讓更多人蔘與自動化的一個過程,在我看來,平臺化中,有一個更為關鍵點,就是關鍵字驅動,只有把自動化測試

Docker五種存儲驅動原理應用場景和性能測試對比

Docker 存儲驅動 Docker最開始采用AUFS作為文件系統,也得益於AUFS分層的概念,實現了多個Container可以共享同一個image。但由於AUFS未並入Linux內核,且只支持Ubuntu,考慮到兼容性問題,在Docker 0.7版本中引入了存儲驅動, 目前,Docker支持AUFS

Android自動化測試遇到的問題解決方法(1)

粘貼 png family 學習 再次 jmeter log 初始 mage 編者按:本文是小小小提姆在使用自動化測試工具TestWriter時的一點使用心得~我叫小小小提姆,是一名在IT行業的洪流中力爭上遊的軟件測試員,個人軟件測試擅長方向:1、功能測試(熟悉Fiddle

關於base64編碼的原理實現

一個 replace 編碼範圍 func nco 都是 style bit 如果 我們的圖片大部分都是可以轉換成base64編碼的data:image。 這個在將canvas保存為img的時候尤其有用。雖然除ie外,大部分現代瀏覽器都已經支持原生的基於base64的enco

java設計模式singleton原理實現

最新 不必要 -- 不同 適合 所有 引用 ati cnblogs 題外話:我要變強,要變強,變強,強。 1、 Singleton的應用場景以及為什麽要使用singleSingleton是一生只能有一個實例的對象。只能由singleton自身創建一個實例。外人是無法創建實例

決策樹原理實現

方式 -1 變化 log nbsp 導致 結點 以及 重要 1、決策樹原理 1.1、定義 分類決策樹模型是一種描述對實例進行分類的樹形結構。決策樹由結點和有向邊組成。結點有兩種類型:內部節點和葉節點,內部節點表示一個特征或屬性,葉節點表示一個類。

RPC原理實現

.get 版本 pcs 連接方式 正常 zookeepe list 接口 分布式計算 1 簡介 RPC 的主要功能目標是讓構建分布式計算(應用)更容易,在提供強大的遠程調用能力時不損失本地調用的語義簡潔性。為實現該目標,RPC 框架需提供一種透明調用機制讓使用者不必顯式的

SSO單點登錄原理實現

response dem nbsp boolean 配置文件 實現 有效 ucc ons 1.SSO分類   根據實現的域不同,可以把SSO分為同域SSO、同父域SSO、跨域SSO三種類型。 2.SSO實現原理 a.打開統一的登錄界面 b.登錄,同時向服務器寫入Cookie

線程池的原理實現

execute inter void date() 超過 緩沖 線程池大小 exceptio 調整 1、線程池簡介: 多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。 假設一個服務器完成一項任務所需時間為:T1

線程池原理實現

任務隊列 批量 not alt con 成了 代碼 pla extends 1、線程池簡介: 多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。 假設一個服務器完成一項任務所需時間為:T1

四.HashSet原理實現學習總結

throw map 所有 cti con name 保持 nts equal 在上一篇博文(HashMap原理及實現學習總結)詳細總結了HashMap的實現過程,對於HashSet而言,它是基於HashMap來實現的,底層采用HashMap來保存元素。所以如果對HashMa

五.HashTable原理實現學習總結

容量 區別 存儲 們的 如果 isn cte ash ref 有兩個類都提供了一個多種用途的hashTable機制,他們都可以將可以key和value結合起來構成鍵值對通過put(key,value)方法保存起來,然後通過get(key)方法獲取相對應的value值。一個是

CGLib動態代理原理實現

aop object col 子類 doc pos 輸出 intercept pub JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢,這就需要CGLib了。CGLib采用了非常底層的字節碼技術,其原理是通過字節碼技術為一個類創建子類,

sso簡單原理實現

登錄用戶 會話 例子 www 哪些 java類 pad adb 應對 轉自:http://www.cnblogs.com/ywlaker/ 一、單系統登錄機制 1、http無狀態協議   web應用采用browser/server架構,http作為通信協議。http是無

網站統計中的數據收集原理實現

fun 美的 置配 客戶 etc 分析 獲取 固定 open 網站統計中的數據收集原理及實現 網站數據統計分析工具是網站站長和運營人員經常使用的一種工具,比較常用的有谷歌分析、百度統計和騰訊分析等等。所有這些統計分析工具的第一步都是網站訪問數據的收集。目前主流的數據收

python+selenium自動化測試——瀏覽器驅動

ted body 控制 must settings tao int .html 模式 selenium控制瀏覽器需要下載對應版本的驅動,並把下載好的驅動解壓然後拷貝到python的安裝目錄。 1、chrome 驅動對應版本及下載地址;https://npm.taobao

智能指針原理實現(1)- shared_ptr

red ++ 直接 初始 targe -- div urn 記錄 C++沒有內存回收機制,每次程序員new出來的對象需要手動delete,流程復雜時可能會漏掉delete,導致內存泄漏。於是C++引入智能指針,可用於動態資源管理,資源即對象的管理策略。 一、智能指針類別 智

智能指針原理實現(2)- unique_ptr

unique clas 結束 基礎 無法 body 智能指針 周期 文件 只允許基礎指針的一個所有者。 可以移到新所有者(具有移動語義),但不會復制或共享(即我們無法得到指向同一個對象的兩個unique_ptr)。 替換已棄用的 auto_ptr。 相較於 boost::s

分布式鎖原理實現方式

ack 常用 ima 個數 tar 刪除 不能 cap lock 本文轉自:http://www.hollischuang.com/archives/1716 目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的

【數據結構】ArrayList原理實現學習總結(2)

!= 需要 但是 object count def 原理 arrays 位置 ArrayList是一個基於數組實現的鏈表(List),這一點可以從源碼中看出: transient Object[] elementData; // non-private to si