📜 ⬆️ ⬇️

Testing through abstract classes in TestNG

Introduction


Are you still testing with JUnit and not paying attention to TestNG? Then we go to you.

One of the advantages of TestNG is the ability to create test datasets for one or several tests. But few people use this advantage from @DataProvider as an empty set of test data. What is it expressed in?

Suppose we have a test testData(String value) and the datas method that provides DataProvider. If datas returns us an array of 3 elements, then testData will execute 3 times. But if datas returns us an empty array, then testData will never be executed
Pictures


Let's try to take advantage of this feature.
')

Application framework for testing


Suppose we have a kind of OrganizationLoader class that reads XML files from a certain directory, where each XML is a description of the department with employees and the read data is transformed into an Organization object. ( commit )
Source
 public class OrganizationLoader { private OrganizationLoader() { } public static Organization loader(File orgDirectory) { if (orgDirectory == null || !orgDirectory.exists() || !orgDirectory.isDirectory()) { return null; } final File[] files = orgDirectory.listFiles(); if (files == null || files.length < 1) { return null; } XStream xStream = new XStream(); xStream.processAnnotations(Department.class); Organization organization = new Organization(); List<Department> departments = new ArrayList<>(); for (File file : files) { try { String xml = FileUtils.readFileToString(file, "UTF-8"); Department department = (Department) xStream.fromXML(xml); departments.add(department); } catch (IOException e) { e.printStackTrace(); } } organization.setDepartments(departments); return organization; } } 
 public class Organization { private List<Department> departments; public List<Department> getDepartments() { return departments; } public void setDepartments(List<Department> departments) { this.departments = departments; } } 
 @XStreamAlias("department") public class Department { @XStreamAlias("name") private String name; @XStreamAlias("employees") private List<Employee> employees; public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> employees) { this.employees = employees; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 
 @XStreamAlias("employee") public class Employee { @XStreamAlias("lastName") private String lastName; @XStreamAlias("firstName") private String firstName; @XStreamAlias("middleName") private String middleName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getMiddleName() { return middleName; } public void setMiddleName(String middleName) { this.middleName = middleName; } } 


Test Baseline


So what do we want to test?
  1. The number of processed departments
  2. Number of employees in the dep1 department
  3. The name of the first employee in dep0 for the organization org0
  4. Surname from the second employee in dep2 for the organization org1


Simple tests


Here we write the usual tests without the use of abstractions, so that later there is something to compare commit
Source
 public class Organization0Test { private Organization organization; @DataProvider public Object[][] dataEmployeeCount() { return new Object[][]{{"dep1", 2}}; } @DataProvider public Object[][] dataEmployeeLastName() { return new Object[][]{{"dep0", 0, "empLastName0_0"}}; } @BeforeMethod public void setUp() throws Exception { File fRoot = new File("."); File orgDir = new File(fRoot, "src/test/resources/org0"); Assert.assertTrue(orgDir.exists()); Assert.assertTrue(orgDir.isDirectory()); organization = OrganizationLoader.loader(orgDir); Assert.assertNotNull(organization); } @Test public void testDepartmentCount() throws Exception { Assert.assertEquals(organization.getDepartments().size(), 2); } @Test(dependsOnMethods = {"testDepartmentCount"}, dataProvider = "dataEmployeeCount") public void testEmployeesCount(String depName, int countEmployee) throws Exception { final List<Department> departments = organization.getDepartments(); int i = 0; Department department; do { department = departments.get(i++); } while (!department.getName().equals(depName)); Assert.assertEquals(department.getName(), depName); Assert.assertEquals(department.getEmployees().size(), countEmployee); } @Test(dependsOnMethods = {"testDepartmentCount"}, dataProvider = "dataEmployeeLastName") public void testEmployeeLastName(String depName, int employeeIndex, String lastName) throws Exception { final List<Department> departments = organization.getDepartments(); int i = 0; Department department; do { department = departments.get(i++); } while (!department.getName().equals(depName)); Assert.assertEquals(department.getName(), depName); Employee employee = department.getEmployees().get(employeeIndex); Assert.assertEquals(employee.getLastName(), lastName); } } 
 public class Organization1Test { private Organization organization; @DataProvider public Object[][] dataEmployeeCount() { return new Object[][]{{"dep1", 2}}; } @DataProvider public Object[][] dataEmployeeLastName() { return new Object[][]{{"dep2", 1, "empLastName2_1"}}; } @BeforeMethod public void setUp() throws Exception { File fRoot = new File("."); File orgDir = new File(fRoot, "src/test/resources/org1"); Assert.assertTrue(orgDir.exists()); Assert.assertTrue(orgDir.isDirectory()); organization = OrganizationLoader.loader(orgDir); Assert.assertNotNull(organization); } @Test public void testDepartmentCount() throws Exception { Assert.assertEquals(organization.getDepartments().size(), 3); } @Test(dependsOnMethods = {"testDepartmentCount"}, dataProvider = "dataEmployeeCount") public void testEmployeesCount(String depName, int countEmployee) throws Exception { final List<Department> departments = organization.getDepartments(); int i = 0; Department department; do { department = departments.get(i++); } while (!department.getName().equals(depName)); Assert.assertEquals(department.getName(), depName); Assert.assertEquals(department.getEmployees().size(), countEmployee); } @Test(dependsOnMethods = {"testDepartmentCount"}, dataProvider = "dataEmployeeLastName") public void testEmployeeLastName(String depName, int employeeIndex, String lastName) throws Exception { final List<Department> departments = organization.getDepartments(); int i = 0; Department department; do { department = departments.get(i++); } while (!department.getName().equals(depName)); Assert.assertEquals(department.getName(), depName); Employee employee = department.getEmployees().get(employeeIndex); Assert.assertEquals(employee.getLastName(), lastName); } } 


But we do not want to write a new test for each test suite, almost completely repeating the program code? Therefore, we proceed to the next step.

Writing an abstract test class and implementation of tests from it

Create an abstract class AbstractTests and move all test methods to it. Also, create stub methods for the DataProvider. ( commit )
Source
 abstract public class AbstractTests { protected Organization organization; abstract protected String getOrgName(); @DataProvider public Object[][] dataDepartmentCount() { return new Object[][]{}; } @DataProvider public Object[][] dataEmployeeCount() { return new Object[][]{}; } @DataProvider public Object[][] dataEmployeeLastName() { return new Object[][]{}; } @BeforeMethod public void setUp() throws Exception { File fRoot = new File("."); File orgDir = new File(fRoot, "src/test/resources/" + getOrgName()); Assert.assertTrue(orgDir.exists()); Assert.assertTrue(orgDir.isDirectory()); organization = OrganizationLoader.loader(orgDir); Assert.assertNotNull(organization); } @Test(dataProvider = "dataDepartmentCount") public void testDepartmentCount(int count) throws Exception { Assert.assertEquals(organization.getDepartments().size(), count); } @Test(dependsOnMethods = {"testDepartmentCount"}, dataProvider = "dataEmployeeCount") public void testEmployeesCount(String depName, int countEmployee) throws Exception { final List<Department> departments = organization.getDepartments(); int i = 0; Department department; do { department = departments.get(i++); } while (!department.getName().equals(depName)); Assert.assertEquals(department.getName(), depName); Assert.assertEquals(department.getEmployees().size(), countEmployee); } @Test(dependsOnMethods = {"testDepartmentCount"}, dataProvider = "dataEmployeeLastName") public void testEmployeeLastName(String depName, int employeeIndex, String lastName) throws Exception { final List<Department> departments = organization.getDepartments(); int i = 0; Department department; do { department = departments.get(i++); } while (!department.getName().equals(depName)); Assert.assertEquals(department.getName(), depName); Employee employee = department.getEmployees().get(employeeIndex); Assert.assertEquals(employee.getLastName(), lastName); } } 


And rewrite the classes Organization0Test and Organization1Test , writing there only test datasets:
Source
 public class Organization0Test extends AbstractTests { @Override protected String getOrgName() { return "org0"; } @DataProvider @Override public Object[][] dataDepartmentCount() { return new Object[][]{{2}}; } @DataProvider @Override public Object[][] dataEmployeeCount() { return new Object[][]{{"dep1", 2}}; } @DataProvider @Override public Object[][] dataEmployeeLastName() { return new Object[][]{{"dep0", 0, "empLastName0_0"}}; } } 
 public class Organization1Test extends AbstractTests { @Override protected String getOrgName() { return "org1"; } @DataProvider @Override public Object[][] dataEmployeeCount() { return new Object[][]{{"dep1", 2}}; } @DataProvider @Override public Object[][] dataEmployeeLastName() { return new Object[][]{{"dep2", 1, "empLastName2_1"}}; } } 



Feature times

If the test method fails due to missing data in the DataProvider, then it will still be considered as completed for the dependent tests.
This can be seen in Organization1Test - the test method testEmployeesCount depends on testDepartmentCount , which, according to reports, is not executed, because there is no test dataset for it.

Feature two

Tests are no different from other methods in Java and can also be overridden, thereby building up “trees” from various tests. If readers are interested, then I can lay out an example of such a "tree".

Nuance

If you remove the DataProvider stub in the Abstract Abstract class, then, depending on the sequence of test execution, none of them can be executed or only a part can be executed. There will be no error - just a warning.
An example in a separate branch - the dataDepartmentCount stub was dataDepartmentCount .
picture

Source: https://habr.com/ru/post/224077/


All Articles