Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Page Object Model Best Practices in Selenium

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?

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

like image 347
Amir Ghahrai Avatar asked Nov 03 '11 15:11

Amir Ghahrai


People also ask

What is the use of page object model in Selenium?

Page Object Model, also known as POM, is a design pattern in Selenium that creates an object repository for storing all web elements. It is useful in reducing code duplication and improves test case maintenance.

Which is best page object model or page Factory?

Page Object Model in Selenium WebDriver is an Object Repository design pattern. Selenium page object model creates our testing code maintainable, reusable. Page Factory is an optimized way to create object repository in Page Object Model framework concept.

What are the types of page object model in Selenium?

Page object model (POM) can be used in any kind of framework such as modular, data-driven, keyword driven, hybrid framework etc. A page object is an object-oriented class that serves as an interface to a page of your Application Under Test(AUT).

Why PageFactory is used in Selenium?

Introduction to PageFactory Class in Selenium The major benefit of the @FindBy annotation is that it lets you initialize page elements without using the FindElement (or FindElements) in Selenium. PageFactory class in Selenium also provides the initElements method for initializing the web elements.


3 Answers

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.

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.

like image 166
digitaljoel Avatar answered Oct 31 '22 18:10

digitaljoel


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.

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:

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.

like image 35
Sam Woods Avatar answered Oct 31 '22 18:10

Sam Woods


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 real purpose 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.

like image 33
Ross Patterson Avatar answered Oct 31 '22 17:10

Ross Patterson