您好,登錄后才能下訂單哦!
主要結論
1.測試自動化是一種妥善記錄并具備清晰定義的方法,借此可以反復運行同一套測試腳本。然而與此同時,這種測試自動化腳本還可進一步實現其他更有創意的應用。
2.雖然自動化的分析思維很難實現,但我們的腳本中無疑可以具備一定的隨機性。
3.測試中“隨機性”的具體程度各異:從隨機輸入和參數,再到全面的隨機測試用例,情況不一而足。
4.很難將隨機步驟與相應的驗證措施匹配起來,但我們可以使用不同的驗證策略確保應用程序能夠按照預期工作。
5.隨機測試無法取代主觀或傳統測試技術,但可在回歸測試過程中讓我們對應用程序質量更為自信。
正如Cem Kaner在他的一片教程中所說,探索式測試是一種強調個人自由度和個體測試人員責任的軟件測試方式,可通過將與測試有關的學習、測試設計、測試執行,以及測試結果的理解視作一系列彼此提攜,在項目完整過程中并行執行的活動,借此對測試工作的成果進行持續不斷的優化。
簡而言之,按照他的定義,眾所周知的“軟件質量和消費者(Software Quality and Consumer)”主張為測試人員提供了在項目中按照自己認為合適的方式進行測試的自由和責任。循序漸進地記錄所有規范,這種做法已經不再是必須,原因也很簡單,創意過程基本式無法記錄的,對吧!在他在TestBash 3大會上有關測試中決策工作的演講中,Mark Tomlinson對系統的主觀理解這一想法表示支持。如果將其作為探索式的,基于風險和基于會話的測試技術(可將其稱之為主觀技術)的核心,測試者將能主觀地確定應用程序中可能導致失敗的重要環節。
可以參看這張旋轉舞者的動力學錯覺示意圖:不同時刻內,我們的大腦或判斷舞者以一個特定的順序旋轉:向左或向右。測試工作也會面臨類似情況:我們可能考慮使用不同流程實現相同結果,或相同流程導致雖不同但符合預期的結果,或者,嗯……任何其他結果。
整個測試執行過程所用的主觀技術可以通過各種成熟的分析思維和“隨機性”的優勢加以引導。其中后者是一個更重要的要素,本文,將揭露自動化測試中“隨機化”的神秘面紗。
如果你感覺到學編程有些吃力,但是又對IT行業非常喜愛的話,可以加測試交流群:1017539290,進群免費領取測試學習資料!
明確起見,測試自動化并不是一種創作活動,而是一種妥善記錄且清晰定義的方法,借此可以讓同一套測試腳本反復運行使用。問題在于,我們該如何使用這些測試自動化腳本,同時更更具創意?
產品質量隨時間而變
產品質量模型和所記錄的測試場景可通過特定的狀態機以及外部特性加以概括。這一點正是測試自動化所熱愛的。測試自動化所關注的正是根據一些非常具體的測試需求集編寫測試腳本。
這種做法很適合功能性回歸測試:清理、打磨、全新發布,隨后由開發大師創建。姑且將其稱之為Shiny吧。
但經過一段冗長、精疲力竭的開發時間線后(伴隨著多次發布,長達數年的支持,數百個Bug的修復和功能請求等),系統會變成什么樣?
確實,從用戶接口的角度來看,可能非常類似于那種雖然老舊但依然工作良好的系統,但表面之下,這種情況通常被稱之為“大泥球”。
對于這樣的系統,算使用自動化腳本,具體功能的哪些部分依然能獲得和初生產發布時同等程度的測試?也許只有30%-80%的部分可以吧。那么其他功能呢?不知道。
當然,此時簡單的辦法可能是審查所有現有的質量文檔,改良原有的場景,(即時)引入新的場景等。但考慮到業內的經驗,隨著遺留系統的規則測試文檔逐漸過時,雖然更新工作依然重要,但這種做法并非總是可行。
為測試自動化解決方案打造妥善定義的架構
下圖是一個精簡的測試自動化解決方案的范例圖,其中包含三層(類似于基于UI、業務邏輯和數據庫實現業務應用程序的方法):UI/API映射、業務裸機,以及測試腳本。
1.UI/API映射代表該解決方案的技術端:UI自動化工具程度與自動化系統的UI高度綁定,這一層所用的方法可能類似于focus()、type_text()、click_button()。
2.業務邏輯是一種由來自業務操作的關鍵字組成的庫。業務操作是指可以在應用程序中執行的某個步驟(如login()、create_user()、validate_user_created())。
3.測試腳本負責執行一系列鏈再一起的業務步驟。
深入了解獨立測試(Separate Test)
考慮這樣一種簡單的記錄測試用例:執行這個 – 驗證這個,執行那個 – 驗證那個,執行某某 – 驗證某某。合格的自動化開發者會創建一系列類似下面這樣的方法:
do_that(), verify_that(), do_this(), verify_this(), do_bla().
測試腳本會按照某種特定的順序調用這樣的方法:
mySpecifiedCase_1(){
do_that();
verify_that();
do_this();
verify_this();
do_bla();
verify_that();
verify_this();
}
由于腳本沒找到任何Bug,我們在某些特定階段的任務變成讓它查找潛在的系統問題。
隨機化方法1 – 裸隨機
從業務角度來說,自動化解決方案中任何步驟都是有效的。因此探索式測試使得我們可以自由地在任何時間點執行任何步驟。這些步驟的混搭也很簡單。我們需要在執行過少數幾次測試后,遵循已實現步驟打造“隨機”測試用例。
輸入:解決方案中所有業務方法的數量,要生成的測試腳本數量,生成每個測試腳本所需步驟數量。
輸出:類似于下列腳本:
myRandomCase_1(){
do_that();
do_bla();
verify_this();
}
很明顯,算某些測試用例可能(甚至已經)成功運行,大部分依然會失敗,因為大量用例實際上是在試圖完成無效操作。如果還沒執行過do_this(),那么verify_this()無疑會失敗。
隨機化方法2 – 有先決條件的隨機方法
這種方式的想法在于只有在工作流中已包含先覺步驟后,才向工作流中加入后續步驟,但這需要對代碼庫進行必要的擴充,確保測試案例生成器可以理解并保證準確的序列。為此可在方法之上添加特性或注解:
@Reguires(do_this)
verify_this()
{…}
這樣我們得到了:
myRandomCase_2(){
do_bla();
do_this();
verify_this(); //can be added, because prerequisite step is already in test
}
這是一種更可預測的方法。但如果do_this()和verify_that()需要在同一個Page1上執行,而do_bla()已經到了Page2又該怎樣?
此時我們面臨一個新問題:verify_that()會失敗,因為無法找到執行所需的控制/上下文。
人工隨機化方法3 – 上下文感知
如果你感覺到學編程有些吃力,但是又對IT行業非常喜愛的話,可以加測試交流群:1017539290,進群免費領取測試學習資料!
測試生成器必須了解執行位置上下文(例如Web開發中的“頁面”)。當然,此時也可以通過特性/注解為生成器提供活躍上下文。
@ReguiresContext(pageThis)
verify_this()
{…}
@ReguiresContext(pageThis)
do_this()
{…}
@ReguiresContext(pageThis)
@MovesContextTo(pageThat)
do_bla()
{…}
本例中do_this()和verify_this()不會放在將上下文改為pageThat的方法,或上下文為pageThat的方法之后。
因此我們可以得到一個類似下面這樣的測試腳本:
myRandomCase_3(){
do_this();
do_bla();
do_that();
}
或者也可以通過方法鏈實現。假設業務方法返回的對象為頁面,測試案例生成器會持續追蹤執行“步驟”前后瀏覽器中顯示的頁面,因此可以確定需要調用驗證或“步驟”方法的正確頁面。這種方法需要額外檢查以驗證流程是否正確,但這個操作可以無須注解實現。
篩選恰當的用例
至此介紹的方法已經可以生成相當大量的測試用例。
主要問題在于,驗證過程本身,以及驗證失敗的測試場景是否是應用程序內的Bug,而非自動化測試腳本邏輯導致的,這些工作也需要耗費大量時間。
因此可以實現一種“預言”類,借此預測所獲得的結果是否滿意,或是否代表任何錯誤信息,并且必要時可進行后續分析。然而本例我們選擇了一個略微不同的方法。
可以通過下列這一套規則代表應用程序的失敗是Bug引起的:
1.500錯誤或類似頁面
2.JavaScript錯誤
3.“未知錯誤”或因為誤用造成的類似的錯誤信息
4.應用程序日志中有關異常和/或錯誤情況的信息
5.發現與任何其他產品有關的錯誤
本例中,可在每個步驟執行完畢后驗證應用程序狀態。因此自動生成的腳本看起來是這樣的:
myRandomCase_3(){
do_this();
validate_standard_rules();
do_bla();
validate_standard_rules();
do_that();
validate_standard_rules();
}
其中validate_standard_rules()方法可以搜索上文提到的各種問題。
注意:通過與OOP結合,這種方法會顯得更為強大,可以檢測出實際的Bug。在Page Object超類實現常規檢查需要查找“常規問題”,例如JavaScript錯誤、日志中的應用程序錯誤等。對于與特定頁面有關的合理檢查,可以繞過這種方法額外增加針對具體頁面的檢查。
實驗
為了進行實驗,我們決定使用公開的郵件系統。考慮到Gmail和Yahoo的流行度,這些系統中所有存在的Bug都已被發現的可能性相當高。因此我們選擇了ProtonMail。
Taking Over Random
假設自動化解決方案已經位,我們“采用”了Shiny系統的自動化測試機制:首先建立一個通用的Java/Selenium測試項目,其中包含幾個使用Page Object模式實現的冒煙測試。隨后按照佳實踐,所有業務方法可以返回一個新的Page Object(針對業務方法結束時依然顯示在瀏覽器中的頁面)或當前Page Object,除非頁面被更改。
為進行自動化探索式測試,我們增加了包含在explr.core包中的類,其中感興趣的當屬TestCaseGenerator和TesCaseExecutor。
TestCaseGenerator
為了生成新的“隨機”測試用例,可以通過TestCaseGenerator類調用兩個generateTestCase方法之一。這兩個方法都能以參數的方式接受代表所生成測試用例中“步驟驗證對”數量的整數。第二個方法還可額外接受一個代表要使用的“驗證策略”數量的參數(第一個方法使用默認策略,本例為USE_PAGE_SANITY_VERIFICATIONS)。
驗證策略代表在向測試用例添加“檢查”步驟時所用的方法。目前我們有兩個選項:
1.USE_RANDOM_VERIFICATIONS:第一個,同時也是明顯的策略。該策略的想法在于,使用來自頁對象的當前驗證方法。但不足之處在于嚴重依賴上下文。例如:我們隨機選擇了一個方法來驗證特定主題的消息是否存在。首先,我們必須知道要查找哪個主題。為此我們引入了@Default注解和DefaultTestData類。DefaultTestData包含的常規測試數據可用于隨機測試。@Default注解可用于將該數據綁定給特定的方法參數。隨后我們需要確保包含該主題的消息先于驗證操作已存在(可在執行該規范的過程中,或之前的任何測試過程中創建)。為此可通過@Depends注解告訴TestCaseGenerator檢查特定方法的調用,如果當前步驟之前沒找到則直接添加。此外我們還需要確保消息沒有在驗證之前刪除。我們發現對于生成的測試用例,依賴性問題大幅降低了隨機化程度,并且這種方法的穩定性也無法滿足要求。
2.USE_PAGE_SANITY_VERIFICATIONS:該策略可檢查顯而易見的應用程序失敗,如顯示了錯誤的頁,錯誤信息,JavaScript錯誤,應用程序日志中的錯誤等。在依賴性方面這個策略更靈活,可在需要時實現針對具體頁的檢查,例如已經足夠靈活到可以找出實際的Bug。目前我們將其用作默認的驗證策略。
TestCaseGenerator類可按照類名搜索Page對象:每個名稱中包含“Page”字符串的類都會被看作是頁對象。頁對象的所有公開方法會被視作業務方法。名稱包含“Verify”字符串的業務方法會被視作驗證,所有其他方法會被視作測試步驟。@IgnoreInRandomTesting注解可用于從列表中排除某些工具方法或整個頁對象。
隨后可從兩個列表中隨機選擇方法生成測試用例:一個列表包含測試步驟,一個列表包含驗證步驟(如果所選驗證策略需要驗證步驟的話)。選擇第一個方法后,將檢查其返回值是否為另一個頁對象。如果返回值是另一個頁對象,那么將從其方法中選擇下一個步驟(參見上文備注)。為避免在兩個頁之間循環往復,有一成的概率會跳轉至一個完全隨機的頁面。如果方法使用@Depends注解標注了任何依賴項,則會按需解決這些問題并添加。
為避免出現從當前所顯示頁之外其他對象調用測試方法的情況,生成的測試用例會傳遞一個額外的驗證,借此添加缺少的導航調用。
TesCaseExecutor
生成之后,測試用例基本上是一種“類-方法對”列表,可通過特定方式執行或保存。盡管可在運行時執行,但從調試和后續分析的角度來看,保存為文件是一種更好的做法。
如果你感覺到學編程有些吃力,但是又對IT行業非常喜愛的話,可以加測試交流群:1017539290,進群免費領取測試學習資料!
生成的測試用例可通過多種方式執行,可以TesCaseExecutor作為其接口,以SaveToFileExecutor作為的實現,借此可簡單地創建一個代表所生成測試用例的.java文件。令人驚異的是,這種相當簡單的解決方案完全滿足了我們的需求:實現速度快,可對測試結果進行深入分析,并能了解具體的生成方式。的不足在于,必須手工編譯并運行生成的測試用例,不過對于實驗來說,這也算不得什么大問題。
SaveToFileExecutor生成的測試用例代碼可通過模板轉換為可編譯的文件。這樣生成的測試范例如下:
@Test(dataProvider = "WebDriverProvider")
public void test(WebDriver driver){
login(driver);
//****<Generated>****
ContactsPage contactspage = new ContactsPage(driver, true);
InboxMailPage inboxmailpage = contactspage.inbox();
inboxmailpage.sanityCheck();
ComposeMailPage composemailpage = inboxmailpage.compose();
composemailpage.sanityCheck();
composemailpage.setTo("me@myself.com");
composemailpage.send();
inboxmailpage.sanityCheck();
List list = inboxmailpage.findBySubject("Seen that?");
inboxmailpage.sanityCheck();
inboxmailpage.inbox();
inboxmailpage.sanityCheck();
DraftsMailPage draftsmailpage = inboxmailpage.drafts();
draftsmailpage.sanityCheck();
inboxmailpage.inbox();
inboxmailpage.sanityCheck();
inboxmailpage.sendNewMessageToMe();
inboxmailpage.setMessagesStarred(true, "autotest", "Seen that?");
inboxmailpage.sanityCheck();
TrashMailPage trashmailpage = inboxmailpage.trash();
trashmailpage.sanityCheck();
//****</Generated>****
}
SaveToFileExecutor生成的代碼位于<Generated>備注之間,其余代碼由模板添加。
從所執行的操作方面來看,我們生成的用例多樣化程度一般,但只要添加包含更多測試步驟的更多頁對象即可輕松解決。
如果你感覺到學編程有些吃力,但是又對IT行業非常喜愛的話,可以加測試交流群:1017539290,進群免費領取測試學習資料!
在進行過上千個“隨機”測試后,我們發現Protonmail沒什么大問題(例如錯誤頁),但瀏覽器匯報了一些JavaScript錯誤,對于依賴JavaScript進行郵件編解碼工作的系統,這些問題非常重要。很明顯,整個實驗中我們并不能訪問服務器日志,但實驗的角度來說,已經足夠展示出這樣的方法對被測試系統質量的促進能起到多大的作用。
當然,隨機測試無法取代主觀或傳統測試技術,但可在回歸測試過程中讓我們對應用程序質量更為自信。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。