Selenium - 最佳实践 - 页面对象模式&页面工厂

时间:2015-09-17 10:53:25

标签: c# selenium-webdriver automated-tests pageobjects

我从0开始一年以来一直在开发我的项目。我已经达到了一定程度的“维护”水平。\ n'我的框架和测试。 但是,如果我在我的项目中使用良好实践,那么每天我都会有更多疑问。如果经验丰富的人能回答我的问题,那就太好了。大多数情况下,我对Page Object Patter和Page Factory都有疑问。

简短说明:

My Project是一个基于单页的应用程序,用C#,angular.js,javascript编写。驱动程序是一个静态实例,它有一堆额外的mehtods(在下面的代码我只显示2)。每个页面都是在Pages类中初始化的静态实例。 由于上述原因,我不必在Tests类中初始化对象。

问题清单:

  1. 在Pages.cs中初始化静态实例是否很好?在我看来,当我以这种方式做这件事的时候,[测试]更容易重复。

  2. 什么是"真实的"使用PageObject库的优点?只有变量的命名? " [FindsBy(如何= How.Id)]"

  3. 什么是"真实的"使用PageFactory的优点?因为我没有找到任何或我的项目,所以它没用。

  4. 在我的真实项目中,我有一个Base类,子类从中继承,所有子类的常用方法都是在PageBase.cs中编写的。所以我对重复的代码没有问题。

    现在我已经在每个页面中实现了Singleton,因此它与下面代码中使用的appraoch类似(区别仅在于初始化PageObject的方式)

    #region Signleton
    private static StartPage instance;
    
    private StartPage()
    {
    }
    
    public static StartPage Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new StartPage();
            }
    
            return instance;
        }
    }
    #endregion
    
    1. 但是在[Test]中我必须使用变量名称" Instance"并且它不像在Pages.cs中初始化PageObject的方法那么可读。 你同意吗?
    2. 单身实例

      StartPage.Instance.Search();
      

      方法概念:

      Browser.cs

      using OpenQA.Selenium;
      using OpenQA.Selenium.Chrome;
      
      namespace SeleniumTestFramework
      {
          public static class Browser
          {
              public static IWebDriver Driver { get; set; }
              public static bool Initialised { get; set; }
      
              public static void Initialize()
              {
                  string chromeDriverDirectory = @"C:\chromedriver_win32";
                  Driver = new ChromeDriver(chromeDriverDirectory);
                  Initialised = true;
              }
      
              public static void Quit()
              {
                  Driver.Quit();
                  Initialised = false;
              }
          }
      }
      

      LoginPage.cs

      using OpenQA.Selenium;
      
      namespace SeleniumTestFramework.Pages
      {
          public class LoginPage
          {
              private IWebElement screenLogin = Browser.Driver.FindElement(By.Id("onScreenLogin"));
      
              public void OpenLoginModal()
              {
                  screenLogin.Click();
              }
          }
      }
      

      LoginModal.cs

      using OpenQA.Selenium;
      
      namespace SeleniumTestFramework.Pages
      {
          public class LoginPage
          {
              private IWebElement screenLogin = Browser.Driver.FindElement(By.Id("onScreenLogin"));
      
              public void OpenLoginModal()
              {
                  screenLogin.Click();
              }
          }
      }
      

      StartPage.cs

      using OpenQA.Selenium;
      
      namespace SeleniumTestFramework.Pages
      {
          public class StartPage
          {
              private IWebElement surenameInput = Browser.Driver.FindElement(By.CssSelector(".id_surname_startpage_testId + input"));
              private IWebElement searchButton = Browser.Driver.FindElement(By.CssSelector(".search-button.search-customer"));
      
      
              public void Search()
              {
                  surenameInput.SendKeys("1");
                  searchButton.Click();
              }
          }
      }
      

      Pages.cs

      namespace SeleniumTestFramework.Pages
      {
          public static class Pages
          {
              public static LoginPage LoginPage
              {
                  get
                  {
                      var loginPage = new LoginPage();
                      return loginPage;
                  }
              }
      
              public static LoginModal LoginModal
              {
                  get
                  {
                      var loginModal = new LoginModal();
                      return loginModal;
                  }
              }
      
              public static StartPage StartPage
              {
                  get
                  {
                      var startPage = new StartPage();
                      return startPage;
                  }
              }
          }
      }
      

      Tests.cs

      using NUnit.Framework;
      using SeleniumTestFramework;
      using SeleniumTestFramework.Pages;
      using OpenQA.Selenium.Support.PageObjects;
      using System.Threading;
      
      namespace SeleniumTest
      {
          [TestFixture]
          public class Tests
          {
              [SetUp]
              public void Before()
              {
                  if (!Browser.Initialised) Browser.Initialize();
                  Browser.Driver.Navigate().GoToUrl("http://localhost:8080/client/");
              }
      
              [TearDown]
              public void After()
              {
                  Browser.Quit(); 
              }
      
              [Test]
              public void Test_without_static()
              {
                  LoginPage loginPage = new LoginPage();
                  loginPage.OpenLoginModal();
      
                  LoginModal loginModal = new LoginModal();
                  loginModal.Login();
      
                  StartPage startPage = new StartPage();
                  startPage.Search();
              }
      
              [Test]
              public void Test_with_static()
              {
                  Pages.LoginPage.OpenLoginModal();
                  Pages.LoginModal.Login();
                  Pages.StartPage.Search();
              }
          }
      }
      

1 个答案:

答案 0 :(得分:3)

有点讨论。让我们开始吧。

  1. 我认为这是一个品味问题。

  2. Page Object框架的真正优势在于您可以在一个位置隔离特定于页面的信息。这使得直接查找和维护此信息。跨页通用的代码可以放在帮助程序或模块文件中。此公共代码与任何页面的细节无关,因此当WebElement的findElement(By)更改时,此公共代码不会受到影响。如果你考虑一下,不这样做会很疯狂。

  3. PageFactory有三个部分。前两个是在页面特定类中定义的。它们是@FindBy实例,用于定义如何访问该页面上定义的有用WebElements。这些首先使它们易于查找和维护。接下来是支持的测试人员操作,定义为方法。这些方法使用@FindBy实例,这使得它们不受FindBy实例更改的影响。

    public class HomePage { 
      final WebDriver driver;
    
      @FindBy(how = How.NAME, using = "text") private WebElement helloText;
      @FindBy(how = How.NAME, using = "exit") private WebElement exitButton;
    
    public HomePage(WebDriver driver) {
      this.driver = driver;
    }
    
    public void clickExitButton() {
      exitButton.click();
    }
    

    }

  4. 3(续)。现在,在实际的测试脚本(Cucumber中的步骤定义文件)中,您首先使用PageFactory初始化页面实例,然后调用您针对该页面实例定义的测试操作方法来调用这些操作。所以

    public class HomePageExitTest extends TestCase {
      WebDriver driver;
    
      @Before public void setUp() throws Exception {
        driver = new FirefoxDriver();
      }
    
      @Test public void testHomeExit() throws Exception {
        driver.get("yoursite.com");
        HomePage homePage = PageFactory.initElements(driver, HomePage.class);
        homePage.clickExitButton();
      }
    
      @After public void tearDown() throws Exception {
        driver.quit();
      }
    }
    

    请参阅本教程http://www.intexsoft.com/blog/item/34-selenium-webdriver-page-object-pattern-and-pagefactory.html