Ваш APIClass не нужен.
Хорошо задумайтесь над каждым словом Сергея.
Каркас, в котором я смогу добавлять, удалять либо изменять тесты.
Как вы думаете, зачем придумали основные концепции ООП (в частности - наследование и полиморфизм)?
Ну, если глобально, то эти две концепции - для уменьшения количества кода. Инкапсуляция для сокрытия данных.
А теперь проведите параллель с программированием. У нас есть классы Human, Phone, MobilePhone. Логично ли будет осуществлять наследование Human → Phone? А что? Человек ведь умеет звонить, не так ли?
Не логично, но мой вопрос выше был не совсем про это, ввиду того что я наковырял один проект этого паттерна (и при этом довольно известный человек его писал) и реализовывал у себя похожую ситуацию. Так вот там что-то сродни этому… Там я вижу одно, а тут я слышу другое. И хотя, то что я здесь слышу, вполне логично, у меня возникает вопрос, почему человек который 10 лет (или около того) пишет фреймворки, пишет их по-другому и наследуется и пейджами и тестами от одного класса ConciseAPI
? Вы как люди опытные наверняка сможете объяснить почему так, может есть какие-то причины?
Если проанализировать среднестатистический пользовательский сеанс в браузере, какие типовые операции выполняет юзер по отношению к компонентам сайта? Учитывая, что в его арсенале имеются только клавиатура и мышка. Найдется ли место в этом списке операции find (в том виде, в котором она представлена у вас)?
А вот про это я думал буквально вчера. Да, мне бы хотелось на будущее писать тесты более высокоуровневые и называть, соответственно, методы более понятно другому человеку. Но это касается страницы тестов GoogleTest
, которую может прочитать любой человек (и понять что здесь), а вот названия методов, которые вы привели - это страница, которую разрабатываю я, как автоматизатор и другим людям читать ее не надо)) Хотя, и тут наверное тоже надо улучшать названия.
А что за зверь вообще такой - этот static? Каковы были первопричины его использования? Как вы думаете, чем вообще может быть чревато неправильное его использование?
Использовал статик исключительно в целях того, что это должен был быть единственный объект для всего фреймворка. Мало ли я где-нибудь по незнанию передам не то что надо, или еще какой экземпляр драйвера нарисуется - в общем, говорю как на духу - первопричину.
За неправильное использование не знаю… Читал какие-то статьи, но давненько было, думаю такие вещи чреваты в более серьезных проектах уровня интерпрайз, а не в простых тестовых фреймворках))
P.S.
О технических ошибках, пожалуй, упоминать не буду, т.к. тут итак хватает информации для пищеварения.
А я бы и за технические упомянул - чем больше, тем лучше.
Кто мне еще скажет?
И, кстати, в ссылке на гитхаб, которую я привел, объект драйвер фигурирует на странице тестов. Вот как это? Начал переписывать свой фрэймворк, возникла такая же проблема - для создания новых объектов на тестовой странице используются конструкторы классов у которых параметром идет драйвер, соответственно он уже фигурирует в тестовом сценарии, что нехорошо, как здесь писали, и с чем я в общем-то согласен, только пока не нашел, как обойти это…
Уберите параметр драйвера из конструктора
Я смотрю, что нынче стало модным обзывать “фреймворком” все, что только в голову придет. Как вы думаете, что означают слова “generic” / “reusable” в классическом определении фреймворка? И как вообще сочетаются эти понятия с добавлением, удалением или изменением тестов?
Тесты, ровно как и PageObjects, являются domain specific слоем, который ну никак нельзя отнести к универсальной составляющей какого-либо абстрактного фреймворка.
Завтра вас попросят автоматизировать процессы поиска ошибок для другого доменного слоя / браузеров / ОС, и что тогда вы будете делать со своим “фреймворком”? Попросите месяцок времени, чтобы адаптировать “готовое” решение под новые требования?
Никому такое не говорите на собеседовании только. Пока вы не разберетесь, как / в какой момент / зачем применять все эти концепции + паттерны проектирования, об изобретении своих фреймворков можно смело забыть.
Вообще не показатель. Проекту 2 года. Проект мог затачиваться под какой-то базовый курс для фрешеров. Или быть ориентированным на презентацию конкретно PageObject темы, а не архитектуры построения фреймворка.
К тому же, хорошему специалисту свойственно постоянно совершенствовать свои скиллы, переосмысливать подходы, подстраиваться под современные тенденции разработки и тестирования. Ведь мир не стоит на месте.
Лично я 2 года назад имел совсем другие взгляды на многие вещи. И порой, пересматривая свой код, могу смело сказать, что будь у меня такая же задача сейчас, я бы написал совсем иначе.
И опять мимо. Дело вовсе не в названии методов, а в уровне детализации, которую вы выносите на поверхность. Зачем тому, кто создает пейджи, метод find? Вы проектируете фреймворк, который по задумке должен упрощать жизнь тем, кто его использует.
Внимание, вопрос: зачем заставлять пользователя фреймворка вызывать 2 (!) операции, вместо одной, каждый раз, когда необходимо выполнить определенное действие над элементом?
Разве не проще написать:
click(element);
А как там будет этот элемент искаться - кого это волнует? Вас, как архитектора, - может быть. Но вы напишите это 1 раз, и забудете. А человек, который будет потом регулярно этим пользоваться, только “спасибо” вам скажет за то, что упростили ему задачу.
Ну если вы, как разработчик, не понимаете, как / что и куда передавать, чтобы не возникало этих “мало ли”, то что же тогда другим ожидать от вашего фреймворка?
Вы выбрали совершенно верный путь к полной потери контроля над своим “детищем”. Вопрос времени. Но иногда и это полезно для того, чтобы осознать и преосмыслить многие вещи, а затем вернуться в строй с новыми силами и энтузиазмом.
[Resolved] Зачем нужен static в java: Зачем нужен static java - automated-testing - #6 от пользователя mindjin
Вот сделал следующую версию.
Структура проекта такая:
Класс GoogleTest
package com.google.test;
import com.google.pages.*;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
public class GoogleTest extends BaseTest {
@Test
public void googleSearchTextByEnter() {
GoogleHomePage homePage = new GoogleHomePage(getDriver());
GoogleSearchResultsPage resultPage = homePage.searchByEnter("Selenium");
assertEquals(resultPage.getFirstLinkText(), "Selenium - Web Browser Automation");
}
@Test
public void googleSearchTextByClick() {
GoogleHomePage homePage = new GoogleHomePage(getDriver());
GoogleSearchResultsPage resultPage = homePage.searchByClick("Selenium");
assertEquals(resultPage.getFirstLinkText(), "Selenium - Web Browser Automation");
}
@Test
public void googleSignInWrongEmail() {
GoogleHomePage homePage = new GoogleHomePage(getDriver());
GoogleSignInPage signInPage = homePage.clickOnSignInButton().inputEmail("selenium@selenium.org");
assertEquals(signInPage.getEmailStatus(), "Couldn't find your Google Account");
}
}
Класс BaseTest
package com.google.test;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
public class BaseTest {
protected WebDriver driver;
protected WebDriver getDriver() {
return driver;
}
@BeforeTest
public void setUp() {
initializeDriver();
setPropertyWindow();
setPropertyTimeOut(); //можно закоментить при использовании assertThat() для всех элементов
}
@AfterTest
public void tearDown() {
delay(3000);
driver.close();
}
public void initializeDriver() {
DesiredCapabilities capabilitiesFirefox = new DesiredCapabilities();
capabilitiesFirefox.setCapability("marionette", true);
System.setProperty("webdriver.gecko.driver", "e:\\Autotests\\TestGoogle\\src\\test\\resources\\Geckodriver 0.16.1\\geckodriver.exe");
driver = new FirefoxDriver(capabilitiesFirefox);
}
public void setPropertyWindow() {
driver.manage().window().maximize();
}
public void setPropertyTimeOut() {
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
public void delay (long millisec) {
try {
Thread.sleep(millisec);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Класс GoogleHomePage
package com.google.pages;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
public class GoogleHomePage extends BasePage {
@FindBy (how = How.XPATH, using = "//input[@name='q']")
private WebElement fieldSearch;
@FindBy (how = How.NAME, using = "btnG")
private WebElement buttonSearch;
@FindBy (how = How.XPATH, using = "//a[text()='Sign in']")
private WebElement buttonSignIn;
public GoogleHomePage(WebDriver driver) {
super(driver);
}
public GoogleSearchResultsPage searchByEnter(String text) {
driver.get(baseURL);
fieldSearch.sendKeys(text, Keys.ENTER);
return new GoogleSearchResultsPage(driver);
}
public GoogleSearchResultsPage searchByClick(String text) {
driver.get(baseURL);
fieldSearch.sendKeys(text);
buttonSearch.click();
return new GoogleSearchResultsPage(driver);
}
public GoogleSignInPage clickOnSignInButton() {
buttonSignIn.click();
return new GoogleSignInPage(driver);
}
}
Класс GoogleSearchResultsPage
package com.google.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import static org.openqa.selenium.support.ui.ExpectedConditions.*;
public class GoogleSearchResultsPage extends BasePage {
@FindBy (how = How.XPATH, using = "//div[@class='srg']//a[text()='Selenium - Web Browser Automation']")
private WebElement firstLink;
public GoogleSearchResultsPage(WebDriver driver) {
super(driver);
}
public String getFirstLinkText() {
return assertThat(visibilityOf(firstLink)).getText();
}
}
Класс GoogleSignInPage
package com.google.pages;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import static org.openqa.selenium.support.ui.ExpectedConditions.*;
public class GoogleSignInPage extends BasePage {
@FindBy (how = How.ID, using = "identifierId")
private WebElement emailInputField;
@FindBy (how = How.XPATH, using = "//div[contains(text(), 'find your Google Account')]")
private WebElement emailStatusField;
public GoogleSignInPage(WebDriver driver) {
super(driver);
}
public GoogleSignInPage inputEmail(String email) {
emailInputField.sendKeys(email, Keys.ENTER);
return this;
}
public String getEmailStatus() {
return assertThat(visibilityOf(emailStatusField)).getText();
}
}
Класс BasePage
package com.google.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class BasePage {
protected WebDriver driver;
protected String baseURL = "https://www.google.com/ncr";
protected long timeOutInSeconds = 10;
public BasePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public WebElement assertThat(ExpectedCondition<WebElement> condition) {
return (new WebDriverWait(driver, timeOutInSeconds)).until(condition);
}
}
Осталось сделать
Они и не знают.
Вы шутите?
public class BaseTest {
protected WebDriver driver;
.....................................
public void initializeDriver() {
А вы? Хотите провести инициализацию драйвера без указания самого двайвера?
Вам что-бы сесть в машину и поехать нужно знать как работает ГРМ?
Если у вас есть, чем мне помочь, тогда помогите и подскажите как.
Если вы только самоутвердиться заходите в эту тему на фоне меня, тогда ладно…
Selenide
Если не секрет, то в чем проблема, если оставить драйвер в базовом тест-классе? Конкретно в разрезе тестов для web-ui?
Нет такого разреза “web-ui” - есть хорошая архитектура и не очень.
При плохой архитектуре тоже можно писать код - но не много и не долго.
Я бы уже после второго написания строки GoogleHomePage homePage = new GoogleHomePage(getDriver());
выкинул бы этот getDriver()
“на мороз”.
Driver
/ \
Test --- Page
Test -> Page -> Driver
Ну смотрите, зачем просто тестам что-то знать о драйвере? Тесты работают по факту с пейджами (объектами) или хелперами, в этих вещах собственно лежит бизнес логика, реализация. Там-то и юзаем тот самый драйвер…
Тест должен знать только то, что есть страница, которую надо открыть или хелпер, который надо дернуть, затем перейти на другую и из нее что-то проверить.
В пейджах можете юзать драйвер, хелперах можете юзать драйвер. Как-то так…
Dы главное не переживайте и не паникуйте
Смотрите, поищите разные реализации на гитхабчике - Search · selenium framework · GitHub
это самый идеальный вариант, посмотреть как делают другие, там конечно может быть много не оч хороших решений. Но вы уже спрашивали и примерно представляете, что лучше избавляться от драйвера в тестах. Поищите там хорошие примерчики, посмотрите много разных. Посмотрите, как разные люди решают проблему.
как примерчик:
- GitHub - ggasoftware/gga-selenium-framework: Automation testing using Selenium WebDriver and Java (примерчики там замудренные, но чтобы вы понимали, что можно подглядеть разные реализации и как люди делают)
рано или поздно придете к Selenide Придет понимание, что писанина собственного селенида забирает кучу времени и дебага, если вы не оч опытный разработчик
Я когда-то подумал, зачем тратить столько времени, если в контексте моих проектов, бизнесу пофигу на чем там у меня тесты написаны, но с селениде получается на много быстрее и проще их писать.
Но на собеседованиях вопросы по селениду вряд ли будут, а вот по WebDriver, будут… Как раз анализ чужого кода хорошо помогает в развитии.
Добрался до ПК, а то с телефона вообще ничего не рассмотреть было.
Вообще, код в последнем примере слегка странный. Драйвер объявлен и в BasePage и в BaseTest. То ли опечатка при спешке, то ли путаница у человека.
Пассажи про [quote=“vmaximv, post:41, topic:13952”]
При плохой архитектуре тоже можно писать код - но не много и не долго.
[/quote]
Для меня мало, что значат. Но вот это уже меняет дело: [quote=“vmaximv, post:41, topic:13952”]
Я бы уже после второго написания строки GoogleHomePage homePage = new GoogleHomePage(getDriver()); выкинул бы этот getDriver() “на мороз”.
[/quote]
Первое отдает маркетинговым буллшитом, а второе - реальный пример проблемы и её исправления. И тут уже сразу понятно почему так делать не комильфо и от какой проблемы избавляемся.
Плохо - значит вы не видите ситуацию в целом, но видите и пытаетесь решить локальную проблему.