[小北De編程手記] [Lesson 02] AutoFramework構建 之 Page Objects - 設計模式

寫在最前面

  這個系列的主旨是要跟你們分享一下關於自動化測試框架的構建的一些心得。這幾年,作了一些自動化測試框架以及團隊的構建的工做。過程當中遇到了不少這樣的同窗,他們在學習了某一門語言和一些自動化測試的類庫或者工具以後,打算進一步的提升。我想這個系列也許會幫助到你,咱們一塊兒從各個維度來看一看自動化測試框架的一些最佳實踐。本人能力有限,若是有什麼不正確的的地方還各位大牛指正。html

自動化測試 - 設計模式

    設計模式(Design pattern)表明了最佳的實踐,是針對一些特定場景下問題的解決方案。設計模式是軟件開發人員在軟件開發過程當中面臨的通常問題的解決方案。這些解決方案是衆多軟件開發人員通過至關長的一段時間的試驗和錯誤總結出來的。這是網絡上比較通用的對設計模式的解釋。git

那麼,對於自動化測試架構來講又有哪些最佳實踐呢?github

  • 領域驅動設計(Domain Driven Design):用接近終端用戶的語言來表達你的測試。
  • 頁面對象(Page Objects):基於UI的簡單抽象。
  • 組件化(Loadable Component):組件化項目中的待測試元素。
  • 基於命令的測試(Bot Style Tests):基於命令而不是對象的設計,對Page Objects的補充
  • 驗收測試(Acceptance Tests):使用粗粒度的UI測試來幫助結構開發工做。
  • 迴歸測試(Regression Tests):將多個驗收測試的操做收集到一個地方以方便維護。

注意:這裏的「驗收測試」和「迴歸測試」是指對自動化測試用例的組織方式,而不是一般意義上的測試過程。雖然這也會成爲實際測試活動的一部分。編程

    這個系列重要內容之一,就是爲你們一一講解上面的模式。 所以,這一個小節我會放在以後全部關於自動化設計模式問文章開頭,由於他真的很重要~~~ 關於上述模式的總結,你在也能夠在Selenium項目的Wiki裏找到,連接以下: https://github.com/SeleniumHQ/selenium/wiki/Design-Patternsjson

PageObject模式目的

    這一篇,咱們要討論的是上述模式中最有名,也是最被誤用最多的模式:Page Objects。簡而言之,Page Objects是咱們針對頁面以及頁面相關服務的封裝。對於使用者來講,每個封裝好的頁面對象都爲他們提供了獲取頁面數據和頁面相關的操做方法。讓使用者能夠簡單的像手工操做同樣的來書寫自動化測試的用例。設計模式

咱們來回顧一下上一講中的那個例子:網絡

 1 namespace AutoFramework.TestCase
 2 {
 3     public class TestSuite_Demo : TestBase
 4     {
 5         public TestSuite_Demo(TestContextFixture context, ServiceFixture service, DBFixture database) 
 6         : base(context, service, database) { }
 7 
 8         [Fact(DisplayName = "TestCase.Demo001")]
 9         public void Demo_Case_Create()
10         {
11             //-->Data preparation.
12             var userModel = ModelBuilder.ForJsonFile<UserModel>("DemoCase/TestData.json");
13 
14             //-->Test case exec way 01.
15             var signInPage = Router.GoTo<SignInPage>();
16             var homePage = signInPage.SignIn("user-name", "pwd");
17             var addUserPage = homePage.NavMenu.Select<AddUserPage>("User", "New");
18             var userListPage = addUserPage.AddUser(userModel);
19             
20             //-->Test case exec way 02.
21             /*You can custom this 'Workflow'*/
22             var userListPage = Router.GoTo<SignInPage>()
23                 .SignIn("user-name", "pwd")
24                 .NavMenu.Select<AddUserPage>("User", "New")
25                 .AddUser(userModel);
26             
27             Assert.True(userListPage.IsExistUser(userModel.Name));
28         }
29     }
30 }

    其中,signInPage,homePage,addUserPage,userListPage 都是一些頁面對象。對於書寫Test Case 的人而言,他們能夠不須要過多的關心頁面上的實現細節。而是,更加關注業務自己。這也是框架設計的目的之一:分層架構

    自動化測試目的主要是模擬手工操做,而不少測試框架好比Selenium,Appnium,white... ...等都提供了基本的驅動支持。在實際自動化構建測試構建過程當中,UI改變致使的測試用例運行失敗應該是自動化須要解決的首要問題,而PageObjects的好處之一,就是能夠較好應對UI的改變對測試用維護成本的影響。框架

PageObject模式原則

上一個小節,咱們看到了如何使用封裝好的PageObject對象。那麼,應該如何來設計(封裝)一個PageObject呢?下面列出了一個些PageObject設計的原則:工具

  • 提供公共方法來表示頁面提供的服務
  • 儘可能不要暴露頁面的內部細節
  • 通常不要在Page Objects中使用斷言(CheckPoint),由於檢查點每每是測試用例應當關心的。
  • 提供頁面操做的方法返回其餘PageObjects
  • Page Objects不須要完整的表達整個頁面,也能夠是一個組件。
  • 相同操做的若是結果不一樣,應當建立不一樣的方法。

仍是以登陸頁面爲例:

 1 public class SignInPage : PageObjectBase
 2 {
 3     public SignInPage(IWebDriver driver) : base(driver)
 4     {
 5         WaitSelector.WaitingFor_ElementExists(this.Driver,By.Id("ContentPlaceHolder1_txtUsername"));
 6 
 7         txtUserName = new TextBox(driver, By.Id("txtUsername"));
 8         txtPassword = new TextBox(driver, By.Id("txtPassword"));
 9         btnSignIn = new Button(driver, By.XPath(".//input[@value='Sign In']"));
10     }
11     
12     #region Page elements     
13     protected TextBox txtUserName;
14     protected TextBox txtPassword;
15     protected Button btnSignIn;
16     #endregion Page elements
17 
18     #region Action for test case
19     /// <summary>
20     /// Sign In
21     /// </summary>
22     /// <param name="userName">User name</param>
23     /// <param name="password">Password</param>
24     public HomePage SignIn(string userName, string password)
25     {
26         this.txtUserName.Clear();
27         this.txtPassword.Clear();
28 
29         this.txtUserName.SendKeys(userName);
30         this.txtPassword.SendKeys(password);
31         this.btnSignIn.Click();
32 
33         return new HomePage(this.Driver);
34     }
35     
36     public SignInPage SignInError(string userName, string password)
37     {
38         this.txtUserName.Clear();
39         this.txtPassword.Clear();
40 
41         this.txtUserName.SendKeys(userName);
42         this.txtPassword.SendKeys(password);
43         this.btnSignIn.Click();
44 
45         return new this(this.Driver);
46     }
47     #endregion
48 }

    能夠看到,對於登陸頁面的實現。基本的頁面操做(好比登陸),若是行爲是不一樣的建議提供兩個不一樣的方法。登陸成功返回的是HomePage。可是若是失敗了返回的是當前頁面。這樣的編碼方式既清晰,也同時知足了前面例子中的鏈式調用的簡潔。

    在方法的內部,咱們須要處理頁面的等待延時處理,元素查找等一系列與UI相關的操做。所謂Page Objects的封裝,就是但願使用Page Objects的人不須要關心頁面上的細節。

關於檢查點,不少實現是在Page Objects內部提供了一些方法來檢查,例如:

1 public SignInPage CheckErrorMessage(string message)
2 {
3     //... ...
4     Assert.True(message,"xxxx");
5 
6     return new this(this.Driver);
7 }

    咱們來思考一下,斷言檢查也就是檢查Check Point應該由是測試用例自己負責,仍是由提供頁面服務的Page Objects來負責呢?很明顯咱們不該該在Page Objects內部處理測試用例的檢查點。下面的這種處理方式是Page Objects模式自己建議的更好的作法:

讓咱們如下面的這個UI爲例:

 1 public string GetErrorMessage()
 2 {
 3     //返回頁面上的錯誤信息
 4 }
 5 
 6 //調用代碼
 7 ...
 8 var signInPage = Router.GoTo<SignInPage>();
 9 var errorMsg = signInPage.SignIn("user-name", "pwd").GetErrorMessage();
10 Assert.Equal(errorMsg,"用戶名密碼錯誤!");

設計模式的使用都有它的場景的意圖。Page Objects模式的設計意圖主要就是爲了解決一下幾個問題:

  • 重用操做
  • 使得自動化測試用例的編寫不用關心過多的UI相關的細節
  • 應對UI的變化

    細心的同窗也許已經注意到了,UI的操做咱們並無直接是用Selenium的WebElement,而是作了一些封裝。使用了相似Button,TextBox 這樣的對象。這一部分涉及到的是咱們後面要講到的另外一個設計模式Loadable Component 和 Bot Style Tests, 後面的課程會對這個專門進行講解。

這一篇就先到這裏啦~~,自動化測試框架的構建是須要必定知識基礎和自動化測試經驗的。但願咱們能在接下來的這段時間裏一塊兒提升,希望個人觀點對你有所幫助~~~

小北De系列文章:

  《[小北De編程手記] : Selenium For C# 教程

  《[小北De編程手記]:玩轉 xUnit.Net》(未完成)

若是您認爲這篇文章還不錯或者有所收穫,能夠點擊右下角的 【推薦】按鈕,由於你的支持是我繼續寫做,分享的最大動力!
做者:小北@North
來源:http://www.cnblogs.com/NorthAlan
聲明:本博客原創文字只表明本人工做中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關係。非商業,未受權,貼子請以現狀保留,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
相關文章
相關標籤/搜索