Have a look at this page class:
public class ResultsPage {
private WebDriver driver;
private static final String RESULTS_PAGE_URL =
"https://vpl.bibliocommons.com";
//element locators
public ResultsPage(WebDriver driver) {
this.driver = driver;
}
public String getUrl() {
}
public boolean isDisplayed() {
}
public String getResultsFound() {
}
public void goToNextPage() {
}
public void goToPreviousPage() {
}
public void goToPage(int pageNumber) {
}
public By getPageXpath(int pageNumber) {
}
public void checkBookFilter() {
}
public void uncheckBookFilter() {
}
public By getFilterXpath(String filterName) {
}
public void selectFilter(String filterName) {
}
public void changeSortOrderByAuthorAscending() {
}
public void changeSortOrderByAuthorDescending() {
}
public void changeSortOrderByTitleAscending() {
}
public void changeSortOrderByAuthorDescending() {
}
public void changeSortOrder(String sortOrder) {
}
public int getResultsPerPage() {
}
public void expandSearch() {
}
public void clickExpandSearchButton() {
}
}
This class has one big problem.
All its methods are declared as public.
Why is this not a good thing?
If all methods of a class are public, the class has no "secrets" from its "users".
No "secrets" means no "privacy", no "boundaries", no "safety", lots of dependencies.
Any other class or method can use the page class in any way they like.
Having all methods declared as public also means that the users of the class can change the class’s objects state. If the class has public setters, through them, the users can modify any data that is encapsulated in the objects of the class. Modifying the state of the page objects leads usually to unstable Selenium code.
Finally, if all methods of the page class are public, the Selenium tests are very dependent on the page methods. Any change in a page method breaks potentially a Selenium test. There is no way that you can make changes in the page class without having side effects.
What is the solution?
A class provides services to its users.
Instead of allowing its users to access everything, it should only make a small set of services available and everything else not available.
How do we do this?
A typical class has 3 types of methods:
constructor (needed for creating objects of the class)
public methods (services that the class offers to its users)
private methods (internal services of the class, used by the public services)
The solution is deciding what are the services that the class offers to its users. These should be the public methods. All other methods should be private and provide support to the public methods.
Coming back to our sample page class, which page methods are the services that the class offers to its users?
These would be the methods that are used in the Selenium tests.
For example,
isDisplayed() {
getResultsFound() {
goToNextPage() {
goToPreviousPage() {
goToPage(int pageNumber) {
checkBookFilter() {
uncheckBookFilter() {
changeSortOrderByAuthorAscending() {
changeSortOrderByAuthorDescending() {
changeSortOrderByTitleAscending() {
changeSortOrderByAuthorDescending() {
getResultsPerPage() {
expandSearch() {
What about the other methods?
getUrl() is used by isDisplayed() so it should be private
selectFilter(String filterName) is used by checkBookFilter() and uncheckBookFilter() so it should be private
changeSortOrder(String sortOrder) is used by changeSortOrderByAuthorAscending(), changeSortOrderByAuthorDescending(), changeSortOrderByTitleAscending()
and changeSortOrderByAuthorDescending() so it should be private
clickExpandSearchButton() is used by expandSearch() so it should be private
getPageXpath(int pageNumber) is used by goToPage() so it should be private
getFilterXpath(String filterName) is used by selectFilter(String filterName) so it should be private
Our class has now a better ratio of public to private methods:
public class ResultsPage {
private WebDriver driver;
private static final String RESULTS_PAGE_URL =
"https://vpl.bibliocommons.com";
//element locators
public ResultsPage(WebDriver driver) {
this.driver = driver;
}
public boolean isDisplayed() {
}
private String getUrl() {
}
public String getResultsFound() {
}
public void goToNextPage() {
}
public void goToPreviousPage() {
}
public void goToPage(int pageNumber) {
}
private By getPageXpath(int pageNumber) {
}
public void checkBookFilter() {
}
public void uncheckBookFilter() {
}
private void selectFilter(String filterName) {
}
private By getFilterXpath(String filterName) {
}
public void changeSortOrderByAuthorAscending() {
}
public void changeSortOrderByAuthorDescending() {
}
public void changeSortOrderByTitleAscending() {
}
public void changeSortOrderByAuthorDescending() {
}
private void changeSortOrder(String sortOrder) {
}
public int getResultsPerPage() {
}
public void expandSearch() {
}
private void clickExpandSearchButton() {
}
}
In conclusion, do not have all page methods from a page class declared as public.
Just a few of them should be public.
All others should be private.