Показаны сообщения с ярлыком Java. Показать все сообщения
Показаны сообщения с ярлыком Java. Показать все сообщения

пятница, 27 марта 2015 г.

Блог жив!

Уважаемые читатели, после долгого переыва у меня наконец-то появилось немного времени для ведения блога. И в ближайшее время постараюсь наполнить его парочкой интересных постов.

понедельник, 11 ноября 2013 г.

Сравнение скорости работы наиболее популярных языков для автоматизации( обновление, добавлен PHP)

Заголовок немного неверный, но не знал как написать лучше. На самом деле мы будем сравнивать байндинги языков для вебдрайвера.

В качестве единого теста для всех будет использоваться один сценарий:


  1. Открываем страницу http://yopolis.ru/site/login
  2. Вводим данные для авторизации
  3. Кликаем по кнопке войти
  4. Проверяем что присутствует элемент со ссылкой на профиль пользователя
 Итак код теста:

Java:

package com.yopolis.tests;


import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.seleniumhq.selenium.fluent.FluentWebDriver;
import org.seleniumhq.selenium.fluent.Period;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.openqa.selenium.By.*;
import static org.seleniumhq.selenium.fluent.Period.secs;


public class YopolisExample {

    Long start=null;
    WebDriver wd=null;
    FluentWebDriver fwd=null;
    Long stop =null;

    @Before
    public void setUp(){
       start = System.currentTimeMillis();
       wd = new FirefoxDriver();
       fwd = new FluentWebDriver(wd);
    }

    @Test
    public void firstTest(){
        wd.get("http://yopolis.ru/site/login");
        fwd.input(id("LoginForm_username")).sendKeys("****@yandex.ru");
        fwd.input(name("LoginForm[password]")).sendKeys("******");
        fwd.button(name("yt0")).click();
        assertThat(fwd.within(secs(5)).has().link(xpath("//a[contains(@href,'/profile')]")),is(true));

    }

    @After
    public void tearDown(){
        wd.close();
        stop = System.currentTimeMillis();
        System.out.println("That took " + (double)((stop - start)/1000) + " seconds");

    }
}



Ruby:

require('selenium/webdriver')

beginning = Time.now
wd= Selenium::WebDriver.for :firefox
wd.navigate.to "http://yopolis.ru/site/login"
wd.find_element(:id,'LoginForm_username').send_keys "****@yandex.ru"
wd.find_element(:name,'LoginForm[password]').send_keys "******"
wd.find_element(:name,'yt0').click
puts wd.find_element(:xpath,'//a[contains(@href,"/profile")]').displayed?
wd.close
puts "Time elapsed #{Time.now - beginning} seconds"


Python:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from datetime import datetime

startTime = datetime.now()

driver = webdriver.Firefox()
driver.get("http://yopolis.ru/site/login")
driver.find_element_by_id("LoginForm_username").send_keys("****@yandex.ru")
driver.find_element_by_name("LoginForm[password]").send_keys("******")
driver.find_element_by_name("yt0").click()

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.XPATH,'//a[contains(@href,"/profile")]')))
driver.quit()

print(datetime.now()-startTime)



WebDriverJs:

var assert=require('assert');
var webdriver = require('selenium-webdriver'),
    SeleniumServer = require('selenium-webdriver/remote').SeleniumServer;

var server = new SeleniumServer('/Users/aalekseev/selenium-server-standalone-2.37.0.jar', {
    port: 4444
});

server.start();

console.time('test exec');

var driver = new webdriver.Builder().
    usingServer(server.address()).
    withCapabilities(webdriver.Capabilities.firefox()).
    build();

driver.get("http://yopolis.ru/site/login");
driver.findElement(webdriver.By.id("LoginForm_username")).sendKeys("****@yandex.ru");
driver.findElement(webdriver.By.name("LoginForm[password]")).sendKeys("******");
driver.findElement(webdriver.By.name("yt0")).click();
var disp=driver.findElement(webdriver.By.xpath('//a[contains(@href,"/profile")]')).isDisplayed();
assert.ok(disp);

driver.quit().then(function(){
    console.timeEnd('test exec');
});

server.stop();

PHP:
Используется: php-webdriver
$start = time();
 
$capabilities = array(WebDriverCapabilityType::BROWSER_NAME => 'firefox');
$driver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $capabilities);
 
$driver->get("http://yopolis.ru/site/login");
 
$driver->findElement(WebDriverBy::id('LoginForm_username'))->sendKeys("****@yandex.ru");
$driver->findElement(WebDriverBy::name('LoginForm[password]'))->sendKeys("******");
$driver->findElement(WebDriverBy::name('yt0'))->click();
 
try {
echo $driver->findElement(WebDriverBy::xpath('//a[contains(@href,"/profile")]'))->isDisplayed();
} catch (NoSuchElementWebDriverError $e) {
}
 
$driver->close();
 
echo "Time elapsed ".(time()-$start)." seconds";
Результаты: Java: 14 секунд
Ruby: 8 секунд
Python: 7 секунд
JS: 20 секунд
PHP: 9 секунд

вторник, 12 февраля 2013 г.

Почему скриптовые языки лучше для автоматизации?

Вопрос в заголовке - это скорее вопрос к пользователям и к самому себе.
С недавних пор перешел с Java на PHP... и понял насколько тяжеловесным был код тестов на java и как тяжело они писались и отлаживались по сравнению с ними-же на PHP.

Я бы хотел услышать в комментариях различные точки зрения на этот счет. Уважаемые читатели если вас не затруднит напишите пару строчек своих мыслей по этому поводу. Заранее огромное спасибо.

Почему я думаю что скриптовые языки лучше:

1. Отсутствует избыточность синтаксиса
2. У динамических языков более широкие возможности для организации кода, нежели у статических. (замыкания, трейты, лямбда-функции)
3. Легкость чтения кода (тут конечно можно поспорить...)

понедельник, 17 декабря 2012 г.

Новые языки в сервисе по генерации Page Object

Недавно обновил сервис. Теперь появилась возможность сгенерировать page object на 4 языках:
  • Java
  • C#
  • Ruby
  • PHP
Историю всех изменения можно прочитать тут.

Уважаемые коллеги-тестировщики! Если у вас есть идеи относительно этого сервиса пишите их мне ) Также приветствуются все кто горит желаниием помочь )

вторник, 14 августа 2012 г.

Перевод статьи по использованию Selenium и JBehave

Оригинал

Driving Web Behaviour

Selenium является мощным инструментом с открытым исходным кодом для автоматизированного тестирования web-приложений. С версии 2.x, он предлагает на выбор два API: API Selenium (обратная совместимость с 1.x) и новый WebDriver API. JBehave поддерживает оба. Когда мы говорим о Selenium, мы обычно подразумеваем сам фреймворк, а если нужно различать API, мы специально обратимся к API и Selenium WebDriver API.
Давайте посмотрим, как мы можем легко использовать Selenium для запуска "веб-историй". Целью создания DSL является представление бизнес-функциональности домена в то же время абстрагируясь от деталей реализации, в этом случае доступ к веб-слою осуществляется с помощью специального инструмента тестирования, такого как Selenium. То же самое DSL должно иметь возможность повторного использования с другими инструментами тестирования.
Как обычно, примеры говорят громче, чем слова:

Scenario: User searches for a single step
Given user is on Home page
When user opens Find Steps page
Then Find Steps page is shown
When user searches for "Given a threshold of 10.0"
Then search returns: "Given a threshold of $threshold"
When user views with methods
Then search returns: "Given a threshold of $threshold,
    [org.jbehave.web.examples.trader.steps.TraderSteps.aThreshold(double)]"
And steps instances include: "TraderSteps,StockExchangeSteps"
TraderWebSteps класс, как и любой другой класс JBehave с шагами, выглядит следующим образом:
public class TraderWebSteps {
    private final Pages pages;
    public TraderWebSteps(Pages pages) {
        this.pages = pages;
    }
    @Given("user is on Home page")
    public void userIsOnHomePage(){       
        pages.home().open();       
    }
    @When("user opens Find Steps page")
    public void userClicksOnFindSteps(){       
        pages.findSteps().open();
    }
    @Then("Find Steps page is shown")
    public void findStepsPageIsShown(){
        pages.findSteps().pageIsShown();
    }
     
    @When("user searches for \"$step\"")
    public void userSearchesForSteps(String step){       
        pages.findSteps().find(step);
    }
    @Then("search returns: \"$stepsOrMethods\"")
    public void stepsFound(List<String> stepsOrMethods){  
        pages.findSteps().found(stepsOrMethods);
    }
    @Then("steps instances include: \"$names\"")
    public void stepsInstancesFound(List<String> names){  
        pages.findSteps().found(names);
    }
}
Новым здесь является то, что мы используем Page Object для абстрагирования от поведения Selenium за страницами, которые определяют взаимодействие с пользователем. Page Object, это то место где происходит магия Selenium. Отметим, что использование страниц до сих пор не позволило нам взять на себя обязательство использования конкретного API, как Selenium API или WebDriver API.

Настройка JBehave для использования Selenium

Как всегда, мы настроим JBehave несколькими различными способами. Один из способов, это иметь встраиваемый запускаемый класс, то есть JUnit-запускаемый класс TraderWebStories. Здесь в игру вступает выбор API.

Использование Selenium API

public class TraderWebStories extends JUnitStories {
   
    private Selenium selenium = SeleniumConfiguration.defaultSelenium();
    private ConditionRunner conditionRunner = SeleniumConfiguration.defaultConditionRunner(selenium);
    private Pages pages = new Pages(selenium, conditionRunner);
    private SeleniumSteps lifecycleSteps = new PerStorySeleniumSteps(selenium);
    private SeleniumContext seleniumContext = new SeleniumContext();
    @Override
    public Configuration configuration() {
        Class<? extends Embeddable> embeddableClass = this.getClass();
        return new SeleniumConfiguration()
            .useSelenium(selenium)
            .useSeleniumContext(seleniumContext)
            .useStepMonitor(new SeleniumStepMonitor(selenium, seleniumContext, new SilentStepMonitor()))
            .useStoryLoader(new LoadFromClasspath(embeddableClass))
            .useStoryReporterBuilder(new StoryReporterBuilder()
                .withCodeLocation(codeLocationFromClass(embeddableClass))
                .withDefaultFormats()
                .withFormats(CONSOLE, TXT, HTML, XML));
    }
    @Override
    public InjectableStepsFactory stepsFactory() {
        return new InstanceStepsFactory(configuration(),
                new TraderWebSteps(pages),
                lifecycleSteps,
                new SeleniumScreenshotOnFailure(selenium));
    }
     
    @Override
    protected List<String> storyPaths() {
        return new StoryFinder()
                .findPaths(codeLocationFromClass(this.getClass()).getFile(), asList("**/*.story"), null);
    }
}

Использование API WebDriver

public class TraderWebStories extends JUnitStories {
   
    private WebDriverProvider driverProvider = new PropertyWebDriverProvider();
    private WebDriverSteps lifecycleSteps = new PerStoriesWebDriverSteps(driverProvider); // or PerStoryWebDriverSteps(driverProvider)
    private Pages pages = new Pages(driverProvider);
    private SeleniumContext context = new SeleniumContext();
    private ContextView contextView = new LocalFrameContextView().sized(500, 100);
     
    public TraderWebStories() {
        // If configuring lifecycle per-stories, you need to ensure that you a same-thread executor
        if ( lifecycleSteps instanceof PerStoriesWebDriverSteps ){
            configuredEmbedder().useExecutorService(MoreExecutors.sameThreadExecutor());
        }
    }
    @Override
    public Configuration configuration() {
        Class<? extends Embeddable> embeddableClass = this.getClass();
        return new SeleniumConfiguration()
                .useSeleniumContext(context)
                .useWebDriverProvider(driverProvider)
                .useStepMonitor(new SeleniumStepMonitor(contextView, context, new SilentStepMonitor()))
                .useStoryLoader(new LoadFromClasspath(embeddableClass))
                .useStoryReporterBuilder(new StoryReporterBuilder()
                    .withCodeLocation(codeLocationFromClass(embeddableClass))
                    .withDefaultFormats()
                    .withFormats(CONSOLE, TXT, HTML, XML));
    }
    @Override
    public InjectableStepsFactory stepsFactory() {
        Configuration configuration = configuration();
        return new InstanceStepsFactory(configuration,
                new TraderWebSteps(pages),
                lifecycleSteps,
                new WebDriverScreenshotOnFailure(driverProvider, configuration.storyReporterBuilder()));
    }
    @Override
    protected List<String> storyPaths() {
        return new StoryFinder()
                .findPaths(codeLocationFromClass(this.getClass()).getFile(), asList("**/*.story"), null);
    }
    // This Embedder is used by Maven or Ant and it will override anything set in the constructor
    public static class SameThreadEmbedder extends Embedder {
         
        public SameThreadEmbedder() {
            useExecutorService(MoreExecutors.sameThreadExecutor());
        }
    }
}

Жизненный цикл шагов

JBehave интеграции с Selenium и WebDriver API, направлена ​​на выполнение общих задач. Среди них одна из самых распространенных является управление жизненным циклом, например, запуском и остановкой браузера.
JBehave предусматривает три типа управления жизненным циклом:
  1. Через истории: через PerStoriesSeleniumSteps или PerStoriesWebDriverSteps .
  2. Через историю: через PerStorySeleniumSteps или PerStoryWebDriverSteps .
  3. Через сценарий: через PerScenarioSeleniumSteps или PerScenarioWebDriverSteps .
Если вы используете контроль жизненного цикла через истории, вы должны убедиться, что вы используете нужный испольнитель.  trader-webdriver пример показывает, как настроить использование одного и того же потока исполнителя.

Запуск Selenium-тестов в автоматическом режиме

ПРИМЕЧАНИЕ: Для запуска Selenium-тестов  в автоматическом режиме, вам нужно запустить два сервера, например Jetty, и Selenium Server (только для Selenium API, для WebDriver API не нужно). См. trader runner selenium example и trader runner webdriver example, отличным способом для того чтобы сделать это будет Maven.

четверг, 19 июля 2012 г.

Горячии вакансии Neoflex



! Java-разработчик
Требования:
·         высшее или неполное высшее техническое образование;
·         опыт разработки J2EE-приложений от 1,5 лет;
·         знание и практическое применение EJB, JMS или WebServices;
·         опыт работы с СУБД (MS SQL Server или Oracle);
·         как плюс – наличие опыта работы с WebSphere Application Server, WebSphere MQ и знание UML, BPEL;
·         английский (на уровне технической документации).


! Специалист по автоматизированному тестированию
Требования:
·         опыт тестирования от 1-го года;
·         опыт автоматизации тестирования с помощью любых инструментов;
·         теоретические знания и опыт программирования на одном из объектно-ориентированных языков (Java, C#, PHP);
·         знание SQL и опыт написания запросов средней сложности;
·         желание профессионально развиваться в направлении автоматизации тестирования и разработке тестовых фреймворков.

! Старший специалист по поддержке интеграционных ИТ-решений (ЕСТП)
Требования:
·         знание SQL(базовый уровень);
·         знание Java (базовый уровень);
·         опыт работы с J2EE серверами приложений;
·         опыт работы с промышленными СУБД (Microsoft SQL Server, Oracle, IBM DB2, Sybase, PostgreSQL и т.д.);
·         опыт поддержки бизнес-систем от 1 года (предпочтителен опыт в поддержке банковских программных продуктов).

вторник, 22 мая 2012 г.

BDD и Selenium

В данной статье пойдет речь о BDD и его применении к тестированию веб-приложений.
Ну и естественно не обойдется без нашего любимого Selenium.

ЧАСТЬ ПЕРВАЯ

Что такое BDD ? Если в двух словах BDD это подход к тестированию и разработке с использованием пользовательских сценариев, как основы для тестов. Данный подход призван сократить расстояние между аналитиками, разработчиками и тестировщиками. 

Подробная информация размещена тут и тут

Мы будем рассматривать библиотеку JBehave.

Как выглядит сценарий тестирования на JBehave ? Это файл с расширением .story и примерно следующего содержания:
Scenario:  trader is not alerted below threshold
Given a stock of symbol STK1 and a threshold of 10.0
When the stock is traded at 5.0
Then the alert status should be OFF
Scenario:  trader is alerted above threshold
Given a stock of symbol STK1 and a threshold of 10.0
When the stock is traded at 11.0
Then the alert status should be ON

Судя по виду не сложно. Сценарии в таком виде позволяют описывать  use-кейсы вполне человеческим языком.

Все предложения в файле должны начинаться со слов Given Then и When.

Предположим мы решили написать для примера небольшую историю для проверки открытия сайта и проверки его заголовка.

Напишем что-то вроде 

Given site http://www.google.com
When title is Google
Then close

и сохраним как behave_example.story

История использования у нас уже есть, теперь перейдем к реализации кода, который скажет браузеру что с этой историей делать.

ЧАСТЬ ВТОРАЯ

Создадим в Eclipse maven-проект. Назовем его JBehaveProj. (не будем цепляться к названию, это только для примера).

В pom.xml в секции dependency запишем следующее

<dependencies>
      <dependency>
          <groupId>org.jbehave</groupId>
          <artifactId>jbehave-core</artifactId>
      </dependency>
      <dependency>
          <groupId>org.seleniumhq.selenium</groupId>
          <artifactId>selenium-java</artifactId>
      </dependency>
  </dependencies>
  <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.jbehave</groupId>
              <artifactId>jbehave-core</artifactId>
              <version>3.6.2</version>
          </dependency>
          <dependency>
              <groupId>org.seleniumhq.selenium</groupId>
              <artifactId>selenium-java</artifactId>
              <version>2.21.0</version>
          </dependency>
      </dependencies>
  </dependencyManagement>

Теперь maven подгрузит нам две библиотеки jbehave-core и selenium-java. Обе они нам понадобятся.

Теперь когда наш проект настроен напишем код.

Создадим класс BehaveTests , этот класс будет содержать имплементацию того что написано в файле .story.

public class BehaveTests {

    FirefoxDriver driver = new FirefoxDriver();

@Given("site $url")   
public void open(String url){
driver.get(url);
}

@When("title is $title")
public void find(String title ){
    if (driver.getTitle().equals(title)){
        System.out.println("Совпало");
       
    }
    else{
        System.out.println("Не совпало");
    }
}

@Then("close")
public void close(){
driver.close();   
}

Надеюсь все что тут написано не вызовет вопросов )))))))) Мы используем аннотации взятые из библиотеки jbehave и говорим с какими фразами из файла .story они должны совпадать.
Слова со знаком $ это переменные, имя переменной должно совпадать с именем параметра в аннотированном методе.

Теперь самое интересное:
Каким способом это все запустить ???????????????????

Для этого напишем еще один класс BehaveExample (название не случайное ).

public class BehaveExample extends JUnitStory  {

        @Override
        public Configuration configuration() {
            return new MostUsefulConfiguration()
                // Ишем истории в Classpath
                .useStoryLoader(new LoadFromClasspath(this.getClass()))
                // Вывод в консоль и текстовый файл
                .useStoryReporterBuilder(new StoryReporterBuilder().withDefaultFormats().withFormats(Format.CONSOLE, Format.TXT));
        }
   
        // Тут опишем наши классы с описанием шагов
        @Override
        public InjectableStepsFactory stepsFactory() {      
                     return new InstanceStepsFactory(configuration(), new BehaveTests());
        }
   
}

для запуска уже почти все готово. Теперь положим наш файл истории рядом с файлом BehaveExample.java. Запустим BehaveExample.java как JUnit тест.

Вуаля )))) Открылся браузер, зашел на гугл, проверил заголовок и закрылся, как раз так как мы и описывали !!!!!!!





вторник, 15 мая 2012 г.

Maven configuration for Java 6

Многие начинающие пользователи maven сталкивались с проблемой что проект в ide собирается, а при сборке из командной строки начинает ругаться на версию Java.
Чаще всего такое поведение вызвано использованием в вашем коде штучек из Java 5,6,7.
Для решения этой проблемы в pom.xml нужно добавить следующие записи:
<properties>
            <java.version>1.5</java.version>
</properties>



И добавить следующие строки в секцию <build>

<plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>

после добавления этих записей все начнет собираться из командной строки без ошибок.

четверг, 3 мая 2012 г.

Учим Properties понимать русский язык

В ходе проекта передо мной возникла необходимость подгружать некоторые значения из файлов. Наиболее простым и быстрым решением показалось считывать эти файлы как объекты Properties.

Но вылезла неприятная особенность, метод Properties.load() по умолчанию загружает все данные в кодировке ISO-8859-1. Это не есть хорошо так как файлы должны содержать кирилицу и после загрузки таким макаром она превращалась в набор кракозябр.

Решение оказалось довольно таки очевидным:

Properties props=new Properties();
props.load(new InputStreamReader(new FileInputStream("system.props"), "UTF-8"));

При загрузке таким образом кириллица остается кириллицей ))

суббота, 28 апреля 2012 г.

Заставляем браузер ждать пока существует определенный элемент.

Для реализации такой функции в наших тестах нам потребуется класс WebDriverWait и  класс Predicate.

Пишем следующую функцию:

public void waitUntilElementPresent(final String xpath){
        new WebDriverWait(this.driver, 10).until(new Predicate<WebDriver>() {
            public boolean apply(WebDriver arg0) {
                return !arg0.findElement(By.xpath(xpath)).isDisplayed();
            }
        });
    }

При вызове этой функции браузер будет ждать до тех пор пока элемент с xpath, который мы передали, существует.

PS: Небольшая поправка, в данном случае браузер будет ждать 10 секунд.

понедельник, 16 апреля 2012 г.

Запись выполнения тестов

При выполнении тестов может возникнуть такая неприятная ситуация, тест как будто бы провален, но нет ясности о причинах провала теста.

В такой ситуации нам бы очень помогла запись того как исполнялся тест.

Слава богу есть такая возможность )))))

Нам следует обратиться вот к этому проекту.

Собственно весь проект нам не нужен. Скачиваем файлы screen-recorder-r2.2.jar и screen-player-r2.2.jar.

Добавляем их в build path нашего проекта с тестами.

Создаем в проекте класс Recorder.

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.one.stone.soup.screen.recorder.DesktopScreenRecorder;
import org.one.stone.soup.screen.recorder.ScreenRecorder;
import org.one.stone.soup.screen.recorder.ScreenRecorderListener;

public class Recorder implements ScreenRecorderListener {
    private ScreenRecorder recorder;

    public void start(String filename) throws FileNotFoundException {
        FileOutputStream oStream = new FileOutputStream(filename);
        recorder = new DesktopScreenRecorder(oStream, this);
        recorder.startRecording();
    }

    public void stop() {
        recorder.stopRecording();
    }

    public void frameRecorded(boolean fullFrame) throws IOException {
       
    }

    public void recordingStopped() {
       
    }

}

Данный класс при вызове метода start() будет записывать все что происходит на рабочем столе, до момента пока мы не вызовем stop().

Все это очень хорошо укладывается в тесты при использовании TestNG и его методов @AfterMethod и @BeforeMethod

После того как тест прошел и файл с записью создан мы можем проиграть его с помощью проигрывателя

java- -jar screen-player.jar (file-name)




пятница, 13 апреля 2012 г.

BDD и Java

Недавно я загорелся идеей еще более дистанцироваться от правки кода авто тестов и собственно написания самих тестов (набивания кода).

Захотелось отойти от самого кода и описывать все в виде простых фраз и предложений.
Для этих целей я решил обратиться к BDD.

На хабре и вики есть неплохие статьи описывающие что это такое и с чем его едят.

Мой взор обратился на JBehave.

Вот тут их официальный сайт.
Статья на сайте IBM.

Как только появятся реальные результаты применения этого подхода вместе с Selenium обязательно напишу статью.

вторник, 3 апреля 2012 г.

Использование рефлексии при написании тестов на Selenium

Сегодня я расскажу об использовании рефлексии языка при написании тестов.

Что это и для чего нужно ?

Рефлексия - процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения.

Это бывает необходимо если вы хотите создать достаточно гибкую систему тестов, которая будет легко подвергаться настройке и изменения без внесения изменений в код.

Пример 

Предположим вы написали некий класс, описывающий веб-страницу с использованием Selenium PageFactory
В ходе выполнения тестов выяснилось что местоположение и идентификаторы элементов за аннотированных как @FindBy могут часто меняться. 
Как тогда быть ? 
Постоянно переписывать все аннотации ? 
Или вынести все аннотации по внешний файл с настройками и менять их там без перекомпиляции кода ?

Последний вариант на мой взгляд наиболее приемлем.

 Реализация

Для реализации нашего варианта нам и потребуется рефлексия. 

Будем использовать библиотеку Javassist.
Ее использование дает нам самые широкие возможности по изменению кода в рантайме. Вплоть до изменения аннотаций !!!

пусть у нас в некоем классе описан элемент:

@FindBy(how = How.ID, using = "element_id")
    private WebElement element;

мы хотим в рантайме менять аттрибуты how и using у аннотации.
значения using будем подгружать из файла настроек.

Для этого напишем класс-адаптер:

public class InterfaceAdaptor {

public static Class adapt(String classname) {
        Properties props=new Properties();
        props.load(new FileInputStream(new File(classname+".props"))); //загружаем файл с настройками
        ClassPool pool = ClassPool.getDefault(); // получаем пулл классов

        CtClass cc = pool.getCtClass(classname); // получаем наш класс из пула
        CtField[] fields=cc.getDeclaredFields(); // получаем список всех полей
        ClassFile ccFile = cc.getClassFile(); // получаем сам класс-файл
        ConstPool constpool = ccFile.getConstPool();
        for(CtField f:fields){
            if(props.containsKey(f.getName())){ 
                // если в пропертис находим значение соответствующее имени поля
                // устанавливаем для этого поля аннотацию с нужными нам параметрами
                //новая аннотация перезаписывает старую
                 AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
                 Annotation annot = new Annotation("org.openqa.selenium.support.FindBy", constpool);
                 EnumMemberValue e=new EnumMemberValue(ccFile.getConstPool());
                 e.setType("org.openqa.selenium.support.How");
                 e.setValue("XPATH");
                 annot.addMemberValue("how",e );
                 annot.addMemberValue("using", new      StringMemberValue(props.getProperty(f.getName()),ccFile.getConstPool()));
               
                 attr.addAnnotation(annot); //добавляем аннотация
                 f.getFieldInfo().addAttribute(attr); //добавляем аттрибуты
                //
            }
        }
        return cc.toClass(); // возвращаем новый исправленный класс
    }
}

После того как мы получили класс мы можем опять таки через рефлексию получить его инстанс.
InterfaceAdaptor.adapt("org.your.ClassName").getConstructors()[0].newInstance();

понедельник, 6 февраля 2012 г.

Пишем безопасное ожидание для браузера

Если вы тестируете веб-приложение которое использует тяжелые и долгие ajax-запросы у вас может возникнуть ситуация когда, браузеру необходимо ждать завершения запроса.

Использование метода Thread.sleep() не безопасно. Зачем нам останавливать всю программу если мы можем просто попросить наш браузер подождать?

Лезть в исходный код Selenium мы не будем. Напишем собственный класс реализующий  интерфейс WebDriver.

public final class MyDriver implements WebDriver {


//реализуем все методы WebDriver
//и добавим свой метод

public void sleep(long timeout) {
try {
new WebDriverWait(this, timeout)
.until(new Predicate<WebDriver>() {
public boolean apply(WebDriver arg0) {
return false;
}
});
} catch (Exception e) {
}
}

}

Собственно на этом все. Теперь когда в вашем тест-кейсе будет требоваться ожидание-просто вызовите метод драйвера sleep();