Тестирование через абстрактные методы в TestNG

Вступление Вы всё ещё тестируете с помощью JUnit и не обращаете внимания на TestNG? Тогда мы идём к вам.Одним из преимуществ TestNG является возможность создания тестовых массивов данных для одного или нескольких тестов. Но мало кто использует такое преимущество от @DataProvider как пустой набор тестовых данных. В чём оно выражается?

Допустим у нас есть некий тест testData (String value) и метод datas обеспечивающий DataProvider. Если datas вернёт нам массив из 3-х элементов, то testData выполнится 3 раза. Но если datas вернёт нам пустой массив, то testData не выполнится ни разу

Картинки dee1c0fb665f62bb6e7a4f07f1c2a0e5.png6380ed3fceefee96a6cb6d42c509cff6.png Давайте попробуем воспользоваться данной особенностью.Каркас приложения для тестирования Предположим у нас есть некое класс OrganizationLoader, который читает из некоего каталога XML файлы, где каждый XML представляет собой описание департамента с сотрудниками и прочитанные данные трансформируются в объект Organization. (commit) Исходный код 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 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 departments;

public List getDepartments () { return departments; }

public void setDepartments (List departments) { this.departments = departments; } } @XStreamAlias («department») public class Department { @XStreamAlias («name») private String name; @XStreamAlias («employees») private List employees;

public List getEmployees () { return employees; }

public void setEmployees (List 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; } } Исходные условия для тестов Итак, что мы хотим протестировать? Количество обработанных департаментов Количество сотрудников в департаменте dep1 Фамилию у первого сотрудника в департаменте dep0 для организации org0 Фамилию у второго сотрудника в департаменте dep2 для организации org1 Простые тесты Здесь мы напишем обычные тесты без использования абстракций, дабы потом было с чем сравнить commit Исходный код 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 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 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 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 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); } } Но мы же не хотим для каждого тестового набора писать новый тест, практически полностью повторяя программный код? Поэтому переходим к следующему шагу.Написание абстрактного тест-класса и имплементации тестов от него Создадим абстрактный класс AbstractTests и вынесем в него все тестовые методы. Так же, создадим методы-заглушки для DataProvider. (commit) Исходный код 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 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 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); }

} И перепишем классы Organization0Test и Organization1Test, прописав там только тестовые наборы данных: Исходный код 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»}}; }

} Фича раз Если тестовый метод не выполнился из-за отсутствующих данных в DataProvider, то он всё равно будет считаться выполненным для зависимых тестов.Это можно увидеть в Organization1Test — тестовый метод testEmployeesCount зависит от testDepartmentCount, который, согласно отчетам, не выполняется, т.к. для него нет тестового набора данных.Фича два Тесты ничем не отличаются от прочих методов в Java и их так же можно переопределять, тем самым выстраивая «деревья» из различных тестов. Если читателям интересно, то могу выложить пример такого «дерева».Нюанс Если в абстрактном классе AbstractTests удалить DataProvider-заглушку, то в зависимости от последовательности выполнения тестов, могут не выполниться ни один или выполниться только часть. Ошибки при этом не будет — только предупреждение.Пример в отдельной ветке — была удалёна заглушка dataDepartmentCount. картинка 7c9e55dd0208da54da8434f70e73171e.png

© Habrahabr.ru