Читаю книгу и наткнулся на такой подход в Selenium Webdriver как data driven testing. Можете показать на просто примере использование этого подхода?
Только просьба дать пример с jUnit
4 or 5? Могу Cucumber показать.
junit 4
а вот куумбер я еще не учил, можно на чистом селениуме?
на ютюбе не пробовли искать - так там полно https://www.youtube.com/results?search_query=selenium+data+driven+testing+junit
Selenium это тупо фрейм для имитации действий юзера в браузере. ВСЁ.
Нужен какой-нибудь runner (junit, testng, cucumber), либо пишите свой на чистом языке Java/Scala, etc.
И что? Как это относится к моему вопросу?
Есть 3 подхода это:
- DDT (Data Driven Testing) - этот подход реализуется с помощью TestNG, JUnit и другими.
- BDD (Behaviour Driven Development) - этот подход реализуется с помощью Cucumber, JBehave
- KDT (Keyword-driven testing) - этот подход реализуется с помощью Robot Framework
Я написал только те фреймворки, которые знаю. А то что ты просишь показать пример, так это берешь и гуглишь определенный фреймворк и разбираешь его, в двух словах так не рассказать, как работает каждый фреймворк.
Уважаемый вы что то путаете, а как же examples в BDD? Это самый настоящий DDT подход.
Есть такая коллекция
@Parameterized.Parameters
public static Collection testData() {
return Arrays.asList(new Object[][] {
{ "Testeruser1", "email1@email.com", "password" },
{ "Testeruser2", "email2@email.com", "password" },
{ "Testeruser3", "email3@email.com", "password" },
{ "Testeruser4", "email4@email.com", "password" } });
}
Как фреймворк понимает, что Testeruser1 надо вставить именно в поле USERNAME, email1@email.com в поле EMAIL, password в поле PASSWORD?
Можете на этот вопрос ответить? Потому что по коду, который я запустил нет никакой связи между полями и этими данными с коллекции.
Например
WebElement fname = driver.findElement(By.xpath("//*[@id=\"user[login]\"]"));
fname.click();
fname.clear();
fname.sendKeys(username);
WebElement emailAddress = driver.findElement(By.xpath("//*[@id=\"user[email]\"]"));
emailAddress.click();
emailAddress.clear();
emailAddress.sendKeys(email);
WebElement pass = driver.findElement(By.xpath("//*[@id=\"user[password]\"]"));
pass.click();
pass.clear();
pass.sendKeys(password);
Через рефлексию. Фреймворк знает о классе с тестами (это мы ему говорим при старте), знает что класс параметризирован (об этом мы сказали используя аннотацию класса Parametrized), и знает что для этого конкретного класса нужно использовать метод testData() в качестве источника данных (это он узнает с помощью аннотации Parametrized.Parameters над методом).
Во время выполнения фреймворк делает следующее:
- Находит метод с аннотацией Parametrized.Parameters и вызывает его. В Вашем случает - это метод testData(). Таким образом фреймворк получает массив с массивами данных. Вызов допустим без создания инстанса, так как метод статический.
- Для каждого элемента внешнего массива создает объект тестового класса, вызывая его конструктор рефлективно и передавая в качестве аргументов все элементы внутреннего массива. Также возможен вариант создания объекта через конструктор без аргументов и последующей установкой полей. Опять же, это тоже происходит рефлективно. В обоих случаях - в результате будет создан объект тестового класса с инициализированными полями.
- Находит методы с аннотацией Test и вызывает их. Тоже рефлективно.
JUnit - это open-source инструмент, Вы можете посмотреть как все это работает скачав его исходники.
Очень-очень упрощенно идея “пускателя тестов” реализована вот тут.
Поясните пожалуйста рефлективно что значит?
Но вот скажем есть такие данные
{ "Testeruser1", "email1@email.com", "password" },
{ "Testeruser2", "email2@email.com", "password" },
{ "Testeruser3", "email3@email.com", "password" },
{ "Testeruser4", "email4@email.com", "password" } });
Как фреймворк понимает, что Testeruser1 идет в поле USERNAME, а например не в поле EMAIL? Я не вижу вообще связи между этим
Ваш тестовый класс помечен аннотацией @RunWith(Parameterized.class)
Раннер знает, что в таком классе должен быть статический метод - провайдер данных. Вы его приводили уже:
@Parameterized.Parameters
public static Collection testData() {
...
Из кода видно, что возвращается Arrays.asList(new Object[][] ...
т.е. двумерный массив объектов возвращается как коллекция (список списков). Кажадя строка этой коллекции - отдельный набор данных для теста. Этот метод - ваш провайдер набора тестовых данных. Как уже Вам написали выше, рефлексиво эти данные раннером помещаются в конструктор тестового класса столько раз, сколько строк в вашем двумерном массиве данных.
Посмотрите на конструктор вашего тестового класса. Вероятнее всего в него передается три строковых параметра, вот в первый из них попадет "Testeruser1"
, во второй - "email1@email.com"
, а в третий - "password"
. Это и будет набор для первого кейса.
UPD: По поводу рефлексии (статья на вики). Если совсем просто: раннер JUnit анализирует скомпилированный код и, в зависимости от аннотаций, знает что делать с конкретным методом или классом. Но Вам все же стоит почитать какой-нибудь мануал по JUnit, иначе вопросы будут возникать практически постоянно
Java Reflection API - инструменты, позволяющие узнавать информацию о методах/полях класса во время выполнения программы. Trail: The Reflection API (The Java™ Tutorials)
Но для начала рекомедую не разбираться с этим, а поучить Java с самого начала, понять зачем вообще она была создана и как работает.
То есть я правильно понял, что если я добавлю еще тестовые данные через запятую - так
{ "Testeruser1", "email1@email.com", "password", "secretQuestion" },
то secretQuestion просто будет игнортроваться, так как в конструкторе всего три параметра, а четвертого нет, верно?
Да, правильно. Если Вам нужен еще один параметер, то нужно добавить член класса, куда вы будете его сохранять и, соответственно, инжектировать его через конструктор.
Хотя скорее всего, у вас должно возникнуть исключение. Т.к. конструктор ожидает три параметра, а вы пытаетесь передать 4
Предполагаю что он игнорироваться не будет: не забывайте что я написал выше о том как JUnit создает объект тестового класса. Что будет если у Вас в конструкторе 3 аргумента, а Вы пытаетесь вызвать его с 4-мя?.. Верно, это даже не скомпилируется. Но так как JUnit работает через рефлексию - то во время компиляции еще неизвестно, будет ли корректно вызван конструктор, и компиляция пройдет нормально. Зато во время выполнения это приведет к ошибке.
Так что будьте внимательны. Если у конструктора 3 аргумента - то и параметров должно быть три.