Selenium 页面对象模型链接是否与Cucumber'兼容;小黄瓜是什么?

Selenium 页面对象模型链接是否与Cucumber'兼容;小黄瓜是什么?,selenium,cucumber,specflow,gherkin,pageobjects,Selenium,Cucumber,Specflow,Gherkin,Pageobjects,通过测试自动化的页面对象模型,我们将页面链接在一起,如下所示: WebDriver driver = new WebDriver() HomePage homePage = new HomePage(driver); LoginPage loginPage = homePage.GoToLoginPage(); WelcomePage welcomePage = loginPage.Login(); etc etc google = Project::Pages::Google.new go

通过测试自动化的页面对象模型,我们将页面链接在一起,如下所示:

WebDriver driver = new WebDriver()
HomePage homePage = new HomePage(driver);
LoginPage loginPage = homePage.GoToLoginPage();
WelcomePage welcomePage = loginPage.Login();
etc
etc
google = Project::Pages::Google.new

google.search_for('Hello, World!')
expect(google.found_result?).to_equal(true)
When(/^I have submitted the "Contact Us" form with the following data:$/) do |table|
  rows = table.raw
  row = rows[0]

  contact_us.fill_form({email: row[0], username: row[1], message: row[2]})
  contact_us.submit_message
  expect(browser.title).to_equal("Message Sent!")
end
这样做的最大好处是,如果开发人员更改主页,使其不再链接到登录页面,我可以更新我的主页类,并在运行测试之前查看所有需要更新的测试(有错误)

然而,对于小黄瓜,上面的每一行将形成一个单独的“步骤”,因此是一个单独的方法。因此,如何才能做到这一点


将页面对象类的实例(如homePage、loginPage等)放入cross-gherkin语句持久存储(如specflow POCO或“World”)的唯一方法是什么

好的,在询问了众多开发和测试自动化专家之后,似乎解决方案是继续链接
[例如,WelcomePage WelcomePage=loginPage.loginWithValidUser(validUser)]
是一条可行之路

要跨步骤持久化页面对象的实例(例如上面示例中的welcomePage),您可以使用依赖项注入工具(在Ruby的cucumber实现中创建类似于World extensions的功能)

以下是更多信息:

然而,大多数项目将受益于依赖项注入模块 更好地组织代码并在步骤之间共享状态 定义

SpecFlow(.net官方实现)的更多信息:

最后,我围绕这一领域创建了一个完整的博客,可能会帮助人们,因为小黄瓜/页面对象交互是我非常感兴趣的主题:


在对这个主题进行了大量讨论之后,一个同样合理的替代方法是在使用带有小黄瓜的页面对象模式时不返回新页面的实例。您将失去使用POM通常获得的链接的好处,但可以说代码的可读性更好,复杂性更低。发布这个备选答案,作为一个测试社区,我们可以投票选择哪种方法是人们的首选。

对于大多数网站(可以使用url),在我看来,最好的做法是简单地使用url,而不是通过一个动作来访问相同的url

例如:

# Suggested by OP:
driver = Selenium::Webdriver.for :chrome, prefs: prefs
homepage = Homepage.new(driver)
login = homepage.go_to_login
welcome = login.log_in_as('dave4429')

# My Suggestion:
homepage = Url.new('/')
login = Url.new('/login')
welcome = Url.new('/welcome')
Given I am logged in as "dave4429"
When I have submitted the "Contact Us" form with the following data:
   | dave4429@example.com | David McBlaine | I want to find out more about your Data Protection services, can I talk to a staff member or get a PDF? |
Then an email should be sent to "support@example.com" with the details specified
这意味着您可以从url开始,而不是每次测试都必须从主页开始。您仍然可以使用您建议的方法,但它们将用于其他领域,以确保用户可以通过url以外的方式访问页面

然而,这不是一个一站式解决方案。对于移动和桌面应用程序,您唯一的选择可能是浏览主屏幕,在这种情况下,您建议的方法肯定是您要使用的方法

“页面对象本身不应进行验证或断言。这是测试的一部分,应始终在测试代码中,而不应在页面对象中。”-

我给出的示例是一个非常基本的示例,我很可能会将它们包装到模块和类中,以支持这样的编码:

WebDriver driver = new WebDriver()
HomePage homePage = new HomePage(driver);
LoginPage loginPage = homePage.GoToLoginPage();
WelcomePage welcomePage = loginPage.Login();
etc
etc
google = Project::Pages::Google.new

google.search_for('Hello, World!')
expect(google.found_result?).to_equal(true)
When(/^I have submitted the "Contact Us" form with the following data:$/) do |table|
  rows = table.raw
  row = rows[0]

  contact_us.fill_form({email: row[0], username: row[1], message: row[2]})
  contact_us.submit_message
  expect(browser.title).to_equal("Message Sent!")
end
编辑

除此之外,你似乎对黄瓜和小黄瓜的作用有误解

每个步骤可以有多行代码,因为步骤本身是对步骤中操作的描述

例如:

# Suggested by OP:
driver = Selenium::Webdriver.for :chrome, prefs: prefs
homepage = Homepage.new(driver)
login = homepage.go_to_login
welcome = login.log_in_as('dave4429')

# My Suggestion:
homepage = Url.new('/')
login = Url.new('/login')
welcome = Url.new('/welcome')
Given I am logged in as "dave4429"
When I have submitted the "Contact Us" form with the following data:
   | dave4429@example.com | David McBlaine | I want to find out more about your Data Protection services, can I talk to a staff member or get a PDF? |
Then an email should be sent to "support@example.com" with the details specified
“何时”的定义可能如下所示:

WebDriver driver = new WebDriver()
HomePage homePage = new HomePage(driver);
LoginPage loginPage = homePage.GoToLoginPage();
WelcomePage welcomePage = loginPage.Login();
etc
etc
google = Project::Pages::Google.new

google.search_for('Hello, World!')
expect(google.found_result?).to_equal(true)
When(/^I have submitted the "Contact Us" form with the following data:$/) do |table|
  rows = table.raw
  row = rows[0]

  contact_us.fill_form({email: row[0], username: row[1], message: row[2]})
  contact_us.submit_message
  expect(browser.title).to_equal("Message Sent!")
end
这完全取决于您在定义中分解了多少步骤

编辑#2

我也很清楚,你想做方法链接,通过
联系我们。填写表格({email:row[0],username:row[1],message:row[2]})。提交消息
,这在使用我建议的技术时也不是不可能的,但是,这个链接是否应该用于每个单独的页面,或者是否所有内容都应该包含在一个类或模块中,这个问题只能由您的需要来回答


我的观点是,这会在一个类中投入太多,分解该类会让测试人员获得更多的控制,我最近看到的另一个选择是将页面对象实例存储为静态变量,可以从任何类访问这些静态变量。

这对于Cucumber和Selenium来说可能有点棘手。我为Selenium开发了一种模式,其中包括对
IWebDriver
接口的扩展方法,允许我使用页面对象导航到特定页面。我向SpecFlow依赖注入框架注册
IWebDriver
对象,然后我的步骤定义类可以自由初始化它们需要的任何页面对象

向SpecFlow注册Selenium Web驱动程序 您只需插入before/after场景挂钩即可管理web驱动程序对象:

[绑定]
公共类WebDriverFactory
{
私有只读IObjectContainer;
公共WebDriverFactory(IObjectContainer)
{
this.container=容器;
}
[场景之前]
public void CreateWebDriver()
{
var驱动器=新的色度驱动器(…);
//配置浏览器
集装箱登记员(司机);
}
[赛后]
公共Web驱动程序()
{
var driver=container.Resolve();
if(驱动程序==null)
返回;
//如果需要,请捕获屏幕截图
//var摄影师=(ITakeScreenshot)司机;
driver.Quit();
driver.Dispose();
}
}
然后就是使用
IWebDriver
界面上的一些扩展将步骤定义和页面对象粘合在一起

Selenium页面对象 保持页面对象相互导航。例如,主页允许您导航到“创建博客文章”页面,并返回该页面的页面对象:

公共类主页
{
专用只读IWebDriver;
私有只读WebDriverWait等待;
私有的