自動化測試關鍵字驅動的原理及實現
轉載地址: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