Overview:
As an automation test engineer, you might have noticed that some of our test steps get repeated very often in multiple tests. In such cases, designing the tests in a such a way that it could be reused in multiple workflow is very important. Re-usability allows us to be more efficient & to write better and clean code.
Lets see how we could design reusable tests.
Sample Workflow:
Lets consider a sample application which has below workflows.
- An user can register himself in the application by ordering a product.
- An existing registered user can also order a new product.
- Once a product is ordered, it can be viewed.
- User can logout.
Based on the above requirements, we can come up with different workflows as shown in above picture.
- A new user enters details -> orders a product -> logout
- A new user enters details -> orders a product -> views product -> logout
- An existing user -> orders a product -> views product -> logout
- An existing user -> orders a product -> logout
- An existing user -> views product -> logout
We might be interested in testing all these above workflows. The same workflow should also be tested for different input parameters. For ex: Different types of products, different payment methods like Credit card, promocodes etc. So writing reusuable tests is very important to maintain these tests in future.
Sample Tests:
This article just explains on writing testNG tests. So I assume that we already have Page objects for each page in the above workflow.
- We would like to launch a browser once for the workflow – all other test should reuse the browser instance. So, Lets create a base class which does this. We use TestNG ITestContext object to store the driver instance. so that any other tests can use it later.
public class BaseTest {
private WebDriver driver;
@BeforeTest
@Parameters({ "browser" })
public void setUpDriver(String browser){
driver = DriverManager.getDriver(browser);
}
@BeforeClass
public void storeDriver(ITestContext ctx){
ctx.setAttribute("driver", driver);
}
}
- User Details Page Test should extend the BaseTest – as the workflow can start from the user Registration Page. It retrieves the driver instance from the ITestContext as shown below.
public class UserDetailsTest extends BaseTest{
private WebDriver driver;
private UserDetailsPage userDetailsPage;
@BeforeClass
public void getCtx(ITestContext ctx){
driver = ctx.getAttribute("driver");
}
@Test
public void launch() {
userDetailsPage = UserDetailsPage.init(driver)
.launch();
//validate if the page is loaded
Assert.assertTrue(userDetailsPage.isAt());
}
@Test
public void enterDetails() {
userDetailsPage.enterDetails();
Assert.assertTrue(userDetailsPage.isSubmitButtonEnabled());
}
}
- User Login Test – should extend the BaseTest – as the workflow can start from the user Login Page.
public class UserLoginTest extends BaseTest{
private WebDriver driver;
private UserLoginPage userLoginPage;
@BeforeClass
public void getCtx(ITestContext ctx){
driver = ctx.getAttribute("driver");
}
@Test
public void launch() {
userLoginPage = UserLoginPage.init(driver)
.launch();
//validate if the page is loaded
Assert.assertTrue(userLoginPage.isAt());
}
@Test
public void login() {
userLoginPage.enterCredentials();
Assert.assertTrue(userLoginPage.isAuthenticated());
}
}
- OrderProductTest should NOT extend BaseTest as the user can not start the session from this page. The user will land on this page either after login or user registration page. So, only those tests should extend BaseTest. Once the user lands on ‘Product Search Page’, the user has to navigate till the ‘Order Confirmation’ page as per above our workflow diagram. So, it can be grouped together.
public class OrderProductTest{
private WebDriver driver;
private ProductSearchPage productSearchPage;
private OrderSummaryPage orderSummaryPage;
private OrderConfirmationPage orderConfirmationPage;
@BeforeClass
public void getCtx(ITestContext ctx){
driver = ctx.getAttribute("driver");
}
@Test
public void productSearchTest() {
productSearchPage = ProductSearchPage.init(driver);
Assert.assertTrue(productSearchPage.isAt());
productSearchPage.selectProduct(Products.A);
productSearchPage.goToOrderSummaryPage();
}
@Test
public void orderSummaryTest() {
orderSummaryPage = OrderSummaryPage.init(driver);
Assert.assertTrue(orderSummaryPage.isAt());
orderSummaryPage.enterPaymentDetails();
}
@Test
public void orderConfirmationTest() {
orderConfirmationPage = OrderConfirmationPage.init(driver);
Assert.assertTrue(orderConfirmationPage.isAt());
}
}
- Test for product view.
public class ViewProductTest{
private ProductViewPage productViewPage;
@BeforeClass
public void getCtx(ITestContext ctx){
WebDriver driver = ctx.getAttribute("driver");
productViewPage = ProductViewPage.init(driver);
}
@Test
public void validate() {
Assert.assertTrue(productViewPage.isAt());
}
}
At this point, Your test package might look like this.
TestNG Suite:
Rest is simple. We need to call the above testNG tests in a proper sequence to create the business workflow as shown below. Now we could create N number of workflows by changing the order. In future, if we need to include any validation point, just updating in one reusable test will do.
<suite name="TestNG HyBrid Tests" parallel="none" allow-return-values="true">
<parameter name="browser" value="chrome"></parameter>
<!--
by calling the TestNG reusable tests in a sequence we create different work flows.
-->
<test name="Check for successful user registration by order product A">
<classes>
<class name="com.test.UserDetailsTest" />
<class name="com.test.OrderProductTest" />
</classes>
</test>
<test name="Check for successful user registration by order product B and view Product B">
<classes>
<class name="com.test.UserDetailsTest" />
<class name="com.test.OrderProductTest" />
<class name="com.test.ViewProductTest" />
</classes>
</test>
<test name="Check if existing user can view his product">
<classes>
<class name="com.test.UserLoginTest" />
<class name="com.test.ViewProductTest" />
</classes>
</test>
</suite>
Summary:
In Continous Regression testing, the effort spent on maintenance should be as low as possible. So that team can focus on enhancing the test suite with more automated tests. But most of the time, we see a lot of red flags / failed tests. Mostly it happens due to poorly designed flaky tests. Proper design techniques should be used for Page objects, Tests & Test Data design. Like the Page components, your tests should be also reusable if possible to reduce the maintenance effort and control flaky tests.
Happy Testing & Subscribe 🙂
Hi Vinoth, Could you paste the code of any page class here. It will help me to understand the Page class structure.
Hi, What does the .init(driver) method?
Check here – http://www.vinsguru.com/selenium-webdriver-how-to-design-tests-test-data/