当前位置: 首页 > 知识库问答 >
问题:

如何在页面对象模型类上创建层次结构?

邓阳炎
2023-03-14

这可能是一个非常奇怪的问题,但我甚至不知道如何命名这个问题。我对C#和Selenium很陌生。我已经对它做了一些编码,我很乐意创建一个(quitemessy)测试,它可以按照我想要的方式运行。我想把我的考试安排得更好一点。

我将用这个例子来说明我想要实现的目标:

在登录页面上,我们可以说我有一个“登录”按钮,该按钮打开一个页面,让我输入我的凭证“用户名”和“密码”。

让我们说我想这样编程:有登录的登陆页面与该页面的所有元素,和一个只为登录页面的元素

测试是这样的:

LandingPage.Login.Click();
LandingPage.Login.Username("username");
LandingPage.Login.Password("password";
LandingPage.Login.LoginBtn.Click();

然后,在登录完成后,我可以进行如下操作:

Database. (everything in the database page). (actions or areas i can navigate to)

在这个类上会有一些层次结构。用户名属于login,登录属于LandingPage,等等。我见过这种类型的编码被使用。我开始为我的测试创建一个“页面对象模型”,并希望将其分离,这样我就可以使用上面显示的方法。“LandinPage.cs”将包含登录链接和其他元素,“login.cs”将包含用户名字段、密码和登录按钮,以及其他现在不相关的元素。

我也明白,这不是真正的单元测试,而是更多的集成测试。

我的问题是,这种格式有名字吗?我正在努力寻找这样的,这样我就可以在那里开始我的学习。

共有3个答案

嵇俊德
2023-03-14

我很快就把它放在了一起,所以它在技术上可能不是100%正确的,但这让您了解了如何在登录页和登录页之间进行传递

登陆页。反恐精英

public class LandingPage
{

    IWebDriver driver;
    readonly By loginBtn = By.Id("some_id");

    public LandingPage(IWebDriver driver)
    {
        this.driver = driver;
    }
    
    // below is the important piece, the clickLogIn method returns an instance of the LoginPage where you can continue on
    public LoginPage clickLogIn()
    {
        driver.FindElement(loginBtn).Click();
        return new LoginPage(driver);
    }
}

登录页面。反恐精英

public class LoginPage
{
    IWebDriver driver;
    readonly By userName = By.Id("passwordID");
    readonly By passWord = By.Id("userID");

    public LoginPage(IWebDriver driver)
    {
        this.driver = driver;
    }

    public void Login()
    {
        driver.FindElement(userName).SendKeys("user");
        driver.FindElement(passWord).SendKeys("password");
    }
}

那么您的测试将如下所示:

var landing = new LandingPage(driver);
var loginPage = landing.clickLogIn();
loginPage.Login();

如前所述,不要从字面上理解细节,而是在LandingPage中注释的部分。cs是关于如何从特定页面返回新页面对象的重要部分

寇甫
2023-03-14

页面对象模型模式是名称。页面对象模型设计模式有三个关键概念:

>

  • 将操作公开为封装用户交互的方法。

    使用数据隐藏隐藏内部元素,如定位器和Web元素。

    页面对象上导致从一个页面转换到另一个页面的公共方法应返回表示另一个页面的另一个页面对象。

    LandingPage类应该有一个导航到登录页面的方法,该方法应该返回一个LoginPage对象:

    LandingPage landingPage = new LandingPage(driver);
    LoginPage loginPage = landingPage.NavigateToLoginPage();
    

    然后,LoginPage应具有一个方法,该方法将用户登录,并返回用户应转到下一个页面的页面对象:

    landingPage = loginPage.LogIn("username", "password");
    

    然后在LandingPage对象上进行断言。

    完整的流程看起来像:

    var landingPage = new LandingPage(driver);
    var loginPage = landingPage.NavigateToLoginPage();
    
    landingPage = loginPage.LogIn("username", "password");
    

    您还可以使用方法链接来收紧代码:

    var landingPage = new LandingPage(driver).NavigateToLoginPage()
                                             .LogIn("username", "password");
    

    让登录页面成为着陆页的“子页面”是错误的抽象。它们是单独的页面。一个页面上的操作将用户引导到另一个页面,该页面由Navigate ToLoginPage()LogIn(string, string)上的返回类型表示。

  • 危裕
    2023-03-14

    我读了很多书,但从来没有完全理解你在说什么。相反,我建议您阅读您提到的页面对象模型,并坚持下去。多年来,它一直是行业标准。

    这里有几个链接可以让您从Selenium文档开始。

    https://www.selenium.dev/documentation/en/guidelines_and_recommendations/page_object_modelshttps://github.com/SeleniumHQ/selenium/wiki/PageObjects

    这是马丁·福勒写的。他几乎是现代页面对象的发明者。https://martinfowler.com/bliki/PageObject.html

    对于任何东西,你都必须小心博客,所以答案,等等,在页面对象模型上。并不是每个人都做对了。上面的这些链接很好,我相信你可以找到更多。为了给您一个如何在您的案例中实施它们的快速示例,

    登陆页。反恐精英

    using OpenQA.Selenium;
    
    namespace SeleniumSandbox.PageObject
    {
        public class LandingPage
        {
            IWebDriver Driver;
    
            // this actually isn't a Login button, it's a "Form Authentication" link but for demo purposes...
            private readonly By _loginButtonLocator = By.CssSelector("a[href='/login']");
    
            public LandingPage(IWebDriver driver)
            {
                this.Driver = driver;
            }
    
            public void ClickLogin()
            {
                Driver.FindElement(_loginButtonLocator).Click();
            }
        }
    }
    

    登录页面。反恐精英

    using OpenQA.Selenium;
    
    namespace SeleniumSandbox.PageObject
    {
        public class LoginPage
        {
            IWebDriver Driver;
    
            private readonly By _loginButtonLocator = By.CssSelector("button");
            private readonly By _passwordLocator = By.Id("password");
            private readonly By _usernameLocator = By.Id("username");
    
            public LoginPage(IWebDriver driver)
            {
                this.Driver = driver;
            }
    
            public void Login(string username, string password)
            {
                Driver.FindElement(_usernameLocator).SendKeys(username);
                Driver.FindElement(_passwordLocator).SendKeys(password);
                Driver.FindElement(_loginButtonLocator).Click();
            }
        }
    }
    

    抽样测试。反恐精英

    using NUnit.Framework;
    using OpenQA.Selenium;
    using OpenQA.Selenium.Chrome;
    using SeleniumSandbox.PageObject;
    
    namespace SeleniumSandbox.Tests
    {
        public class SampleTest
        {
            [Test]
            public void LoginTest()
            {
                IWebDriver driver = new ChromeDriver();
                driver.Manage().Window.Maximize();
                string url = "http://the-internet.herokuapp.com/";
                driver.Url = url;
    
                string username = "tomsmith";
                string password = "SuperSecretPassword!";
    
                new LandingPage(driver).ClickLogin();
    
                new LoginPage(driver).Login(username, password);
            }
        }
    }
    

    这使用了Selenium贡献者之一Dave Haeffner创建的示例页面站点,这是一个工作示例。您需要使用以下NuGet包。

    DotNetSeleniumExtras.WaitHelper
    NUnit
    NUnit3TestAdapter(如果您想从Visual Studio中的测试资源管理器运行测试...强烈推荐至少调试测试等。)
    Selenium。支持
    Selenium。Selenium.Web驱动程序。ChromeDriver(或任何你想使用的浏览器)

     类似资料:
    • 我想将Nightwatch的页面对象系统用于我们应用程序中使用的UI组件。因为nightwatch有自己的读取/初始化它们的方式,所以我看不到正确扩展/重用它们的方法。 例如,我想要一个“日期字段”的DateInputPageObject。它将识别标签、输入、日期选择器等。 我会在任何带有日期输入字段的页面上使用它。 我还想扩展页面对象。例如,。将为所有模态元素定义选择器-覆盖、容器、关闭按钮等。

    • 零售商店的正确模式是什么?公司从商店销售产品。 这似乎违反了我对OOP所知的全部知识。通过层次结构向下传递数据的方法--在对象之间复制参数?我错过了什么?

    • 问题内容: 在“深度”对象层次结构中使用Builder模式的最佳实践是什么?详细地说,我探讨了将Joshua Bloch提出的Builder模式应用于我的XML绑定代码的想法(我使用的是SimpleXML,但是这个问题将适用于任何情况)。我的对象层次结构深达4个级别,具有不同程度的复杂性。我的意思是,在某些级别上,我的对象只有几个属性,而在其他级别上,我最多可以有10个属性。 因此,请考虑以下假设

    • 问题内容: 我有一个表,它表示类别层次结构,层次结构顶部的元素的父ID为0。在CatID列中有超过54K个唯一ID。每个ID可以是另一个ID的父对象。类别深入8个级别。该表如下所示: 这就是我想要实现的结果: 我怎样才能做到这一点?我是否需要某种循环才能遍历所有ID? 有人可以帮忙吗? 问题答案: 这里是:

    • 我想不出为继承层次结构创建视图方法。如果我像下面的代码一样创建类层次结构,那么我就不能从bview.set(...)中正确使用B类的方法和属性而不进行强制转换,因为BView是从AView继承的。和Set method signature接受A类型的变量,但在BView中我希望设置B类型的变量。我该如何解决我的问题? 谢谢你。:3

    • 我已经使用Appium和Selenium在Java中创建了一个页面对象,该对象目前正在为Android应用程序工作,如下所示: 但是,我需要它在Android应用程序和iOS应用程序中工作,xpath选择器对于这两个应用程序是不同的。我想我需要这样做: 这意味着不管我使用的是Android系统还是iOS我仍然会使用一个叫做“验证标题”的变量。 然而,当我这样做的时候,司机。findElement行