【问题标题】:Selenium - Best Practices - Page Object Patter & Page FactorySelenium - 最佳实践 - 页面对象模式和页面工厂
【发布时间】:2015-09-17 10:53:25
【问题描述】:

从 0 年开始,我一直在开发我的项目。我的框架和测试已经达到了一定的“维护”水平。 但是,每天我都会怀疑我是否在我的项目中使用了良好的实践。如果有经验的人可以回答我的几个问题,那就太好了。主要是我对页面对象模式和页面工厂有疑问。

简短说明:

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

问题列表:

  1. 在 Pages.cs 中初始化静态实例是一种好方法吗?在我看来,当我以这种方式进行时,[Test] 更容易重复。

  2. 使用 PageObject 库的“真正”优势是什么?只有变量的命名? “[FindsBy(How=How.Id)]”?

  3. 使用 PageFactory 的“真正”优势是什么?因为我没有找到任何东西,或者对我的项目没有用。

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

现在我已经在每个Page中实现了Singleton,所以它与下面代码中使用的方法类似(不同之处只是初始化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 的方法。 你同意吗?

单例实例

StartPage.Instance.Search();

方法的概念:

浏览器.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();
        }
    }
}

【问题讨论】:

  • 我投票结束这个问题,因为它应该被迁移到 corereview.stackexchange.com
  • 这是一个很好的问题......它只是不适合 Stack Overflow 网站。
  • 问你一个问题..如果明天你需要并行化你的测试,你将如何实现你的浏览器实例是静态引用? (眨眼).. 建议总是使用组合而不是继承给你更多的灵活性而不是可读性

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


【解决方案1】:

相当多的讨论。让我们开始吧。

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

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

  3. PageFactory 包含三个部分。前两个在页面特定类中定义。它们是定义如何访问在该页面上定义的有用 WebElement 的 @FindBy 实例。这些是第一位的,这使得它们很容易找到和维护。接下来是定义为方法的受支持的测试人员操作。这些方法使用 @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();
    }
    

    }

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

【讨论】:

    猜你喜欢
    • 2011-12-21
    • 2017-08-09
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多