1 / 31

Бодрящий микс из Selenium и TestNG Р егрессионное тестирование руками разработчиков

Бодрящий микс из Selenium и TestNG Р егрессионное тестирование руками разработчиков. Ребров Андрей Luxoft. @andrebrov. Сколько тестировщиков в вашей команде?. Всегда кажется, что их не хватает. При этом. «У нас agile » - значит, тестирование должно завершиться в том же спринте

coye
Download Presentation

Бодрящий микс из Selenium и TestNG Р егрессионное тестирование руками разработчиков

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Бодрящий микс из Selenium и TestNG Регрессионное тестирование руками разработчиков Ребров Андрей Luxoft

  2. @andrebrov

  3. Сколько тестировщиков в вашей команде?

  4. Всегда кажется, что их не хватает

  5. При этом... • «У нас agile» - значит,тестирование должно завершиться в том же спринте • «Люблю короткие релизы»- значит регрессионное тестирование надо делать постоянно • «Они опять изменили требования!» - значит опять надо менять тесты

  6. Хватит это терпеть!

  7. Задачи • Нужно иметь возможность проводить регрессию в короткий период времени • Тесты должны быть простыми, чтобы их можно было легко написать/дописать/переписать • Поддержка тестов не должна занимать много времени

  8. Необходимые инструменты • Тестовый фреймворк • Фреймворк функционального тестирования • CI Server • + удобная IDE, понятный генератор отчетов,удобный язык программирования...

  9. Что взяли мы • TestNG • Selenium 2 / WebDriver • Spring • IntelliJ IDEA • Jenkins • Набор самописных утилит

  10. Почему TestNG • Удобная работа с данными - @DataProvider • Разбиение тестов по группам • Многопоточность «из коробки» • «Фабрика» тестов

  11. Почему WebDriver • Java-фреймворк • Абстракция на уровне PageObject • Работа с IE & FF • Активно развивается

  12. Зачем Spring? • Облегчение работы с базами данных • Необходима интеграция с различными сервисами в рамках тестов • IoC

  13. Этапы создания тестовой платформы

  14. Создание базового тестового класса public abstract class AbstractSeleniumTestClass extends AbstractTestNGSpringContextTests { @Autowired private WebDriver driver; @BeforeMethod(alwaysRun = true) public void printTestName(Method method) { } @AfterMethod(alwaysRun = true) public void clearCookies(Method method) throws Exception { } protected WebDriver getWebDriver() { } public SearchPage loadLemAndLogin() { } }

  15. Создание базовой web-страницы public abstract class AbstractPage extends LoadableComponent<LoginPage> { public AbstractPage(WebDriver driver) { this.driver = driver; this.wait = new WebDriverWait(driver, DEFAULT_TIMEOUT); PageFactory.initElements(driver, this); } protected abstract By getPageLoadedCheckElementLocator(); // Primitive actions protected void clickOn(WebElement webElement) { } protected void type(WebElement webElement, String text) { } // Keys protected void pressEnter(WebElement webElement) { } protected void pressRight(WebElement webElement) { } // Autocomplete public void fillAutocomplete(WebElement webElement, String text) { } // Waits public WebElement waitUntilFound(final By by) { } }

  16. Описание web-страницы dfpublic class LoginPage extends AbstractPage { private static final Logger log = Logger.getLogger(LoginPage.class); @FindBy(xpath = "//input[@name='USER']") private WebElement usernameInput; @FindBy(xpath = "//input[@name='PASSWORD']") private WebElement passwordInput; @FindBy(xpath = "//input[@class='Button']") private WebElement loginButton; public LoginPage(WebDriver driver) { super(driver); } @Override protected By getPageLoadedCheckElementLocator() { } @Override protected void isLoaded() throws Error { } public SearchPage login() { } }

  17. Вынесение данных в DataProvider public class SearchDataProvider { @DataProvider public static Object[][] searchTypes() { Object[][] result = new Object[4][1]; result[0][0] = "BEGINS_WITH"; result[1][0] = "CONTAINS"; result[2][0] = "CONTAINS_SUBSTRING"; result[3][0] = "SOUNDS_LIKE"; return result; } }

  18. Refactoring • Вынесение текстовых констант из классов страниц • Группировка DataProvider`ов в классы

  19. Подключение базы данных <bean id=“dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.OracleDriver"/> <property name="url" value=""/> <property name="username" value=""/> <property name="password" value=""/> <property name="maxActive" value="10"/> </bean> <bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate"> <constructor-arg ref=“dataSource"/> </bean>

  20. Работа с базой внутри DataProvider`ов @Component public class SearchByAlternateNameDataProvider { private static DataProviderGenerator dataProviderGenerator; @Autowired public void setDataProviderGenerator(DataProviderGenerator dataProviderGenerator) { SearchByAlternateNameDataProvider.dataProviderGenerator = dataProviderGenerator; } @DataProvider public static Object[][] alternateNameAndNonSuitableCOI() { return dataProviderGenerator.generatePairStringString("select …” + Config.DATA_COUNT); } • } @Component public class DataProviderGenerator { @Autowired private TestingJdbcTemplate testingJdbcTemplate; public Object[][] generatePairStringString(String sql) { List<Pair> list = testingJdbcTemplate.getSimpleJdbcTemplate().query(sql, new PairRowMapper()); Object[][] result = new Object[list.size()][2]; int i = 0; for (Pair pair : list) { result[i][0] = pair.getOne().toString(); result[i++][1] = pair.getTwo().toString(); } return result; } }

  21. Хинт 1 – WebDriver как SpringBean @Configuration public class SeleniumConfiguration { @Autowired private WebDriver driver; public @Bean WebDriver driver() { } @PreDestroy public void cleanUp() { try { driver.quit(); } catch (Throwable e) { e.printStackTrace(); } } }

  22. Хинт 2 – TestFactory для похожих тестов public class SearchTestFactory { @Factory(dataProvider = "searchTypes", dataProviderClass = SearchDataProvider.class) public Object[] createTest(String searchType) { return new Object[]{new GenericSearchTest(searchType)}; } } public class GenericSearchTest extends AbstractSeleniumTest { private String searchType; public GenericSearchByLegalNameCOITest(String searchType) { this.searchType = searchType; } @Test(dataProvider = "legalNamesAndCountries", dataProviderClass = SearchTestFactory.class) @JiraIssue(number = “SRC-19") public void test(String param1, String param2) { } }

  23. Хинт 3 – Unit-тест как тест-кейс SearchPage searchPage = loadAndLogin(); searchPage.setLegalNameSearchType(searchType); searchPage.setLegalNameSearchParam(legalName); SearchResultPage searchResultPage = searchPage.submit(); assertIsSortedByLegalName(searchResultPage);

  24. Хинт 4 – Подключаем javascript public void waitForAjaxComplete() { log.verbose("waiting for ajax completion"); wait.until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver driver) { return (Boolean) js.executeScript("return $.active == 0"); } }); log.verbose("All ajax calls are complete"); }

  25. Подключаем Jenkins • Используем возможность запуска через maven • Подключаем отчеты от TestNG и видим результаты регрессии • Запуск тестов по расписанию / установке новой версии / …

  26. Profit!

  27. Куда двигаться дальше • Создание профилей тестирования (smokem full, search) • Selenium Grid и многопоточность • 1 подход – разные типы приложений (WebService, ETL, ...) • End-to-end тестирование

  28. Андрей Ребров • Arebrov@luxoft.com • @andrebrov

More Related