The following 2 tests implement 2 simple test cases:
1st test case:
opens home page
executes a search
selects the 1st product
verifies that, on the product info page, the product name and type are displayed
2nd test case:
opens home page
executes a search
selects the 1st product
places a hold on the product on the product info page
logs in
verifies that the hold is placed
@Test
public void productInfoIsDisplayedOnProductPageTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
assertTrue(homePage.isDisplayed());
ResultsPage resultsPage = homePage.search(keyword);
assertTrue(resultsPage.isDisplayed());
ProductPage productPage = resultsPage.selectProduct(1);
assertTrue(productPage.isDisplayed());
assertTrue(productPage.hasProductName());
assertTrue(productPage.hasProductType());
}
@Test
public void canPlaceHoldOnProductTest() {
HomePage homePage = new HomePage(driver);
homePage.open();
assertTrue(homePage.isDisplayed());
ResultsPage resultsPage = homePage.search(keyword);
assertTrue(resultsPage.isDisplayed());
ProductPage productPage = resultsPage.selectProduct(1);
assertTrue(productPage.isDisplayed());
LoginPage loginPage = productPage.placeHold();
assertTrue(loginPage.isDisplayed());
UserPage userPage = loginPage.loginWith(username, password);
assertTrue(userPage.isDisplayed);
assertTrue(userPage.hasProductHold());
}Both tests are very straightforward:
they start with opening the site, navigate to the page under test where assertions are being executed
the code is object oriented, the interaction with each page being done through a page object
the tests are easy to understand
But, there is some code duplication that is common to both tests.
This code repeats in both tests:
HomePage homePage = new HomePage(driver);
homePage.open();
assertTrue(homePage.isDisplayed());
ResultsPage resultsPage = homePage.search(keyword);
assertTrue(resultsPage.isDisplayed());
ProductPage productPage = resultsPage.selectProduct(1);
assertTrue(productPage.isDisplayed());We may remove this code duplication with a method as follows:
private ProductPage goToProductPage() {
HomePage homePage = new HomePage(driver);
homePage.open();
assertTrue(homePage.isDisplayed());
ResultsPage resultsPage = homePage.search(keyword);
assertTrue(resultsPage.isDisplayed());
ProductPage productPage = resultsPage.selectProduct(1);
assertTrue(productPage.isDisplayed());
return productPage;
}With the new method, the tests become much shorter and have no more duplicated code:
@Test
public void productInfoIsDisplayedOnProductPageTest() {
ProductPage productPage = goToProductPage();
assertTrue(productPage.hasProductName());
assertTrue(productPage.hasProductType());
}
@Test
public void canPlaceHoldOnProductTest() {
ProductPage productPage = goToProductPage();
LoginPage loginPage = productPage.placeHold();
assertTrue(loginPage.isDisplayed());
UserPage userPage = loginPage.loginWith(username, password);
assertTrue(userPage.isDisplayed);
assertTrue(userPage.hasProductHold());
}We solved the code duplication but introduced a new problem.
Now, our tests work at 2 levels of abstraction.
They start with a local method goToProductPage (which relies on 3 page objects) and also use 2 additional page objects directly.
Having a test working at more than 1 level of abstraction is a bad idea and should be avoided.
Why is this a bad idea?
Let’s start with the goToProductPage() method. Without looking at its code, how can one understand what it does? How does the navigation happen to the ProductPage?
Notice also that this new method includes assertions.
In order to understand what assertions are being done by the test, we have to check the test’s assertions and also the goToProductPage’s assertions.
The code is confusing and not easy to understand without going into the goToProductPage() method.
The solution for this problem can be either to
roll back to the original version that uses only page objects
only use local methods
Let’s try the second approach.
See below our tests changed with local methods:
@Test
public void productInfoIsDisplayedOnProductPageTest() {
openHomePage();
search(keyword);
selectProduct(1);
assertTrue(isProductNameDisplayed());
assertTrue(isProductTypeDisplayed());
}
@Test
public void canPlaceHoldOnProductTest() {
openHomePage();
search(keyword);
selectProduct(1);
placeHold();
loginWith(username, password);
assertTrue(isProductHoldDisplayed());
}The tests look pretty good, don’t you think?
But this is not object oriented code.
Also, assertions are hidden inside the local methods.
And if you want to know how each method works, you have to look at its code.
This leaves us the only good option, the original one.
Yes, the tests should only use page objects.
Yes, the tests may have some duplicated code.
This is ok since the tests remain simple, clear and easy to understand.
