java Selenium 中的页面对象模型最佳实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7997858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Page Object Model Best Practices in Selenium
提问by Amir Ghahrai
When you are modelling your page objects, how would you deal with a page which has form and about 50 input fields on it? What is the best practice here?
当您对页面对象建模时,您将如何处理具有表单和大约 50 个输入字段的页面?这里的最佳做法是什么?
Would you create a page object and write a separate function for each input action? or would you write one function which parameters are passed to it and enters the text?
您会创建一个页面对象并为每个输入操作编写一个单独的函数吗?或者你会写一个函数,将参数传递给它并输入文本?
e.g.
例如
public void enterFirstName(String firstName) {
driver.type("firstNameField", firstName);
}
public void enterSecondName(String secondName) {
driver.type("secondNameField", secondName);
}
or
或者
public void fillInForm(String inputFieldName, String text) {
driver.type(inputFieldName, text);
}
I can see in the first model, when writing tests, the tests are more descriptive, but if the page contains too many input fields, creating the page object becomes cumbersome.
我可以在第一个模型中看到,在编写测试时,测试更具描述性,但是如果页面包含太多输入字段,则创建页面对象变得很麻烦。
This post is also quite interesting in structuring selenium tests in Page Objects Functional Automated Testing Best Practices with Selenium WebDriver
这篇文章在使用 Selenium WebDriver构建页面对象功能自动化测试最佳实践中的selenium 测试方面也很有趣
采纳答案by Sam Woods
I always like to break things up into groups of related information. For instance, if I have a user class I might break that up into a few smaller classes: LoginCredentials, ProfileInfo, Settings, etc, but I would still usually have a top level User class that contains these sub classes.
我总是喜欢把事情分解成相关信息的组。例如,如果我有一个用户类,我可能会将其分解为几个较小的类:LoginCredentials、ProfileInfo、Settings 等,但我通常仍然会有一个包含这些子类的顶级 User 类。
One thing I would certainly recommend would be to pass in an object to one FillForm function rather than all of those individual functions. There are some great advantages using this approach. One, you could have some "common" pre-configured objects that you use for many of your test cases. For instance:
我肯定会推荐的一件事是将对象传递给一个 FillForm 函数,而不是所有这些单个函数。使用这种方法有一些很大的优势。第一,您可以拥有一些用于许多测试用例的“通用”预配置对象。例如:
public class FormInfo
{
string Domain;
string Name;
string Category;
// etc...
public FormInfo(string domain, string name, string category)
{
Domain = domain;
Name = name;
Category = category;
// etc...
}
}
// Somewhere in your initialization code
public static FormInfo Info1 = new FormInfo("myDomain1", "myName1", "myCategory1");
public static FormInfo Info2 = new FormInfo("myDomain2", "myName2", "myCategory2");
You can still update one of your common merchants if you need to do something one-off:
// In your test case:
Info1.Category = "blah";
FormPage.FillForm(Info1);
OR, you can create a brand new merchant object for a specific test case if necessary. You can also do things like field validation either using these objects, or what I normally do is break the page object pattern for specific field validation, so if I am validating the merchant domain field I might do this:
或者,如有必要,您可以为特定测试用例创建一个全新的商家对象。您还可以使用这些对象执行诸如字段验证之类的操作,或者我通常做的是破坏特定字段验证的页面对象模式,因此如果我正在验证商家域字段,我可能会这样做:
Info1.Domain = null; //This should make the FillForm function skip doing anything with this field.
FormPage.FillForm(Info1);
FormPage.DomainTextBox.Text = "field validation string";
Another important advantage of this approach is that if the page is ever updated to add, remove or modify fields, you would only need to update your FormInfo object and FillForm function, and would not need to modify specific test cases that call the FillForm function - assuming they are using one of your common FormInfo objects. Another possibility to get more coverage would be to set up one of your common FormInfo objects to generate random strings for each of the fields that comply to the min/max length and cycle between all different allowed characters. This allows you to get some additional testing out of the same set of tests, although it could also add some noise if you start getting failure results only from specific strings, so be careful.
这种方法的另一个重要优点是,如果页面被更新以添加、删除或修改字段,您只需要更新您的 FormInfo 对象和 FillForm 函数,而无需修改调用 FillForm 函数的特定测试用例 -假设他们正在使用您的常见 FormInfo 对象之一。另一种获得更多覆盖的可能性是设置一个常见的 FormInfo 对象,为每个字段生成随机字符串,这些字符串符合所有不同的允许字符之间的最小/最大长度和循环。这允许您从同一组测试中获得一些额外的测试,但如果您开始仅从特定字符串获得失败结果,它也会增加一些噪音,所以要小心。
回答by digitaljoel
The idea behind the page object model is that it abstracts the implementation away from the caller. In the first mechanism, you are successfully doing that because the caller doesn't need to know if the html input field name changes from "firstName" to "user_first_name", whereas in your second implementation any changes to the actual page would have to be trickled out to all callers of your page object.
页面对象模型背后的想法是它将实现从调用者那里抽象出来。在第一种机制中,您成功地做到了这一点,因为调用者不需要知道 html 输入字段名称是否从“firstName”更改为“user_first_name”,而在您的第二种实现中,对实际页面的任何更改都必须是传递给页面对象的所有调用者。
While it may be more work up front to create your page object, if you maintain the encapsulation it'll save work in the long run when the real html page inevitably changes.
虽然创建页面对象可能需要更多的前期工作,但如果您保持封装,从长远来看,当真实的 html 页面不可避免地发生变化时,它将节省工作。
回答by Ross Patterson
In addition to your enterWhatever()
methods, I usually also create a createWhatever(field1, field2, ...)
method, which I can use as a fast path to creating whatever the form builds, for use when the realpurpose of the test is something else. Thus, if I need to create a Customer in order to test submitting a Ticket, the test goes to the CreateACustomer
page and just invokes createCustomer(firstName, lastName, emailAddress, ...)
, and then continues on to the more-nuanced task of creating a Ticket using that Customer.
除了您的enterWhatever()
方法之外,我通常还会创建一个createWhatever(field1, field2, ...)
方法,我可以将其用作创建表单构建的任何内容的快速路径,以便在测试的真正目的是其他目的时使用。因此,如果我需要创建一个 Customer 来测试提交工单,测试会转到CreateACustomer
页面并调用createCustomer(firstName, lastName, emailAddress, ...)
,然后继续执行使用该客户创建工单的更细微的任务。
回答by vins
I am answering an old question for the benefit of readers.
为了读者的利益,我正在回答一个老问题。
Along with other good answers here, I would like to add few suggestions here for those who are new to POM.
除了这里的其他好答案,我想在这里为 POM 的新手添加一些建议。
Page objects is a well known design pattern, widely accepted by the automation engineers, to create separate class file for each page of the application to group all the elements as properties and their behaviors / business functionalities as methods of the class. But it has few issues in creating a class for a page - especially when the page has more / different sets of elements / complex element like a grid / calendar widget / a HTML table etc.
页面对象是一种众所周知的设计模式,被自动化工程师广泛接受,为应用程序的每个页面创建单独的类文件,将所有元素分组为属性,并将它们的行为/业务功能分组为类的方法。但是在为页面创建类时几乎没有问题 - 特别是当页面具有更多/不同的元素集/复杂元素(如网格/日历小部件/HTML 表格等)时。
The class might contain too many responsibilities to handle. It should be restructured and broken into smaller classes. Ie, following the Single Responsibility Responsible.
该类可能包含太多需要处理的职责。它应该被重组并分解成更小的类。即,遵循单一职责负责。
Check the image here for the idea.
检查这里的图像的想法。
That is, create reusable page fragments & let the main page object serve the page fragments.
也就是说,创建可重用的页面片段并让主页面对象为页面片段提供服务。
Check herefor more info.
请点击这里获取更多信息。
回答by Yujun Liang
Please have a look at the readme, https://github.com/yujunliang/seleniumcapsules
回答by CBRRacer
The way I do this in my forms is to get a list of all of the inputs on the page. Then remove any input elements that are not displayed. After that I can put valid or invalid text to each of the inputs. From there I catch the validation summary to make sure I am getting the correct error or not. If not then log exception.
我在表单中执行此操作的方法是获取页面上所有输入的列表。然后删除所有未显示的输入元素。之后,我可以将有效或无效的文本添加到每个输入中。从那里我捕获验证摘要以确保我得到正确的错误与否。如果不是,则记录异常。
What this does is allow me to input text into as many inputs as are on the page, and it still allows me to log exceptions and send them via e-mail. I also catch textareas and password fields in my list and I have a separate list for checkbox fields and Options since there are different things that I usually want to do with those.
这样做是允许我将文本输入到页面上的尽可能多的输入中,并且它仍然允许我记录异常并通过电子邮件发送它们。我还在我的列表中捕获了文本区域和密码字段,并且我有一个单独的复选框字段和选项列表,因为我通常想用它们做不同的事情。
what it boils down to is that all I have to do to test a page is this:
归结起来,我要测试一个页面所要做的就是:
for (int i = 0; i < inputs.Count(); i++)
{
//This captures the error message string created in the input validation method
//nextButton is the IWebElement of the button to click to submit the form for validation
//ErrorMessageID is the ID of the Validation Summary display box (i.e. ErrorMessageID = "FormSummary" <asp:ValidationSummary ID="FormSummary" runat="server" CssClass="errorMessage" />
string InputValidationText = utilities.InputValidation(driver, inputs, i, nextButton, ErrorMessageID)
if(InputValidationText != string.Empty)
{
//LogError
}
}