Saturday, February 25, 2023

Abstracting the Test Layer using TestNG

The library architecture is popular among test automation framework designers. To follow this pattern, engineers decompose and abstract the automation logic at various conceptual levels, such as at the page, the component or at the element level. But usually, the test layer is left out of these decomposition efforts.

Leaving abstraction out of the test layer can in time lead to duplication of the logic as well as having to spend more time than what is required to script new scenarios. This post will discuss how the test layer can be abstracted and decomposed using TestNG.


High-level Steps

  1. Start with designing and implementing test cases so that they are atomic
  2. Encapsulate the test layer by scripting the test steps and adding assertions required to validate the component. Then put a mechanism in place to read the test data from an object that can be passed from one test class to another as required.
  3. Finally, use the Factory feature in TestNG to compose the larger scripts using the test classes.
Let’s take a crude example of validating a web page with a dropdown[1]. For this example, I have identified the two test cases seen below,
  1. Validate that the dropdown page loads the dropdown and that the values are as expected.
  2. Validate that the dropdown allows the user to select the option he wants to select.
The test layers for the two test cases were scripted as seen below and were joined together using the factory annotation in the DropDrownTest class. Notice how the same test data object is passed between the two test cases.


Test Class 1

package com.dumiduh.elements;
import com.dumiduh.constants.Constants;
import com.dumiduh.function.DropDownPageFunctions;
import com.dumiduh.models.TestData;
import com.dumiduh.utils.JSONUtil;
import com.dumiduh.utils.TestBase;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* The objective of this test class is to demonstrate how a dropdown maybe handled.
*/
public class DropDownUsageTest extends TestBase {
@BeforeClass
public static void setup() {
instantiateDriver();
driver.get(Constants.DROPDOWN_PAGE_URL);
}
@Test
public static void dropDownUsageTest() {
TestData testData = DropDownTest.data;
System.out.println("::\t"+ testData.getDropDownSelection());
DropDownPageFunctions dropDownPageFunctions = new DropDownPageFunctions(driver);
dropDownPageFunctions.selectValueFromDropDown(testData.getDropDownSelection());
//Asserts to see if the dropdown selection has been set.
Assert.assertTrue(dropDownPageFunctions.isTheGivenValueSelected(testData.getDropDownSelection()));
}
@AfterClass
public static void cleanUp(){
driver.quit();
}
}


Test Class 2

package com.dumiduh.elements;
import com.dumiduh.function.DropDownPageFunctions;
import com.dumiduh.models.TestData;
import com.dumiduh.utils.JSONUtil;
import com.dumiduh.utils.TestBase;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static com.dumiduh.constants.Constants.DROPDOWN_PAGE_URL;
public class DropDownPageElementsTest extends TestBase {
@BeforeClass
public static void setup() {
instantiateDriver();
}
@Test
public static void dropDownPageElementTest() {
TestData data = DropDownTest.data;
driver.get(DROPDOWN_PAGE_URL);
DropDownPageFunctions dropdown = new DropDownPageFunctions(driver);
Assert.assertTrue(dropdown.isTheDropDownHeadingDisplayed());
Assert.assertTrue(dropdown.isTheDropDownDisplayed());
Assert.assertEquals(data.getNumberOfOptions(), dropdown.getTheListOfOptions()
.size());
if (dropdown.getTheListOfOptions()
.containsAll(data.getListOfOptions())) {
Assert.assertTrue(true);
}
}
@AfterClass
public void cleanUp() {
DropDownTest.data.setDropDownSelection("Option 2");
driver.quit();
}
}


Factory Class

package com.dumiduh.elements;
import com.dumiduh.models.TestData;
import com.dumiduh.utils.JSONUtil;
import org.testng.annotations.Factory;
public class DropDownTest {
static TestData data = JSONUtil.readAGivenTestDataItem("dropdownendtoend");
@Factory
public static Object[] DropDownTest() {
return new Object[]{
new DropDownPageElementsTest(),
new DropDownUsageTest()};
}
}


[1] - https://the-internet.herokuapp.com/dropdown

[repo] - https://github.com/handakumbura/SeleniumAutomationEmployerProfile/tree/feature/atomic_test_cases




What's in my Bag? EDC of a Tester