Автоматизированное тестирование с помощью Selenium и Cucumber

Написание, пакетирование и выполнение автоматизированных тестов RIA-приложений

Использование инструментов Selenium и Cucumber позволяет автоматизировать тестирование путем записи тестов в простые файлы функций и управления ими в браузере. Эта статья является практическим введением в развертывание инфраструктуры автоматизации тестирования на основе инструментов Selenium и Cucumber, создание набора тестов для одностраничных Web-приложений и выполнение тестов в нескольких мобильных и Web-браузерах с использованием Selenium Grid.

Алан Бауэрс, консультант по мобильным и Web-приложениям, IBM

Алан Бауэрс (Alan Bowers) – фотографияАлан Бауэрс (Alan Bowers) работает консультантом по мобильным и Web 2.0-приложениям в группе Software Services for Mobile Team, входящей в состав подразделения IBM Software Group. Он занимает эту должность с апреля 2011 года. За это время Алан проявил себя в широком спектре Web-технологий, особенно в JavaScript, Dojo, JQuery и Worklight, а также в полном жизненном цикле разработки и гибких методологиях разработки. Ранее Алан в качестве Java-разработчика входил в состав небольшой группы гибкой разработки, занимавшейся созданием инструментов диагностики для Java-приложений.



Джеймс Белл, управляющий консультант, IBM

Джеймс Белл (James Bell) – фотографияДжеймс Белл (James Bell), консультант IBM Interactive в рамках Global Business Services, обладает опытом руководства, управления и разработки технических решений. Джеймс участвовал в больших и малых проектах, возглавляя локальные и глобальные группы разработки.



16.12.2013

Неотъемлемой частью жизненного цикла разработки Web-приложений является обеспечение их корректной работы в наборе поддерживаемых браузеров. Для обеспечения совместимости приложений с различными браузерами Web-разработчики традиционно используют экстенсивное регрессионное тестирование, но такой подход является очень затратным с точки зрения времени и ресурсов. Альтернативный подход заключается в создании нескольких наборов полностью автоматизированных тестов для выполнения в ряде браузеров.

Наборы полностью автоматизированных тестов можно создавать и выполнять в рамках запланированного процесса сборки или в рамках конвейера сборки. В любом случае этот подход позволяет выявлять проблемы на ранних стадиях и получать быструю обратную связь. К моменту сборки вы будете уверены в работоспособности кода приложения, что может значительно снизить или даже полностью устранить необходимость в регрессионном тестировании.

В данной статье демонстрируются преимущества использования Selenium и Cucumber для автоматизированного тестирования. Эта инфраструктура позволяет записывать тесты в файлы функций в виде, понятном любому бизнес-менеджеру или другому пользователю, не имеющему технической подготовки. Затем с помощью Cucumber, поддерживающего множество языков сценариев и программирования, тесты преобразуются в Java-код. Selenium используется для управления браузером.

Мы рассмотрим полностью процесс развертывания с помощью Cucumber и Selenium автоматизированной, основанной на Java инфраструктуры тестирования. Мы начнем с создания файлов функций с помощью Cucumber, а затем с помощью Selenium выполним модификацию шаблона Page Object для тестирования RIA-приложения в выбранном браузере. Мы также продемонстрируем настройку тестирования кода приложения в дополнительном браузере, например в Chrome или мобильном браузере. Мы будем автоматизировать набор тестов Maven-сборки приложения, сосредоточившись на создании тестового кода настраиваемого решения.

Используемое в статье RIA-приложение можно загрузить в любой момент.

Тестирование с помощью Cucumber

Cucumber – это инфраструктура тестирования, позволяющая преодолеть разрыв между разработчиками ПО и бизнес-менеджерами. Тесты пишутся на простом языке управляемой поведением разработки (BDD) в стиле Given, When, Then (условия, операция, результат), которой понятен любому пользователю. Затем контрольные тесты записываются в файлы функций, охватывающие один или несколько сценариев тестирования. Cucumber интерпретирует тесты на указанном языке программирования и использует Selenium для управления тестами в браузере. В нашем случае тесты преобразуются в Java-код.

URL-адрес демонстрационного приложения

В примерах данной статьи предполагается, что демонстрационное приложение имеет локальный адрес http://localhost/MockApplication/html/MockApplication.html. При изменении адреса приложения необходимо соответствующим образом изменить тестовый код.

BDD-синтаксис Given, When, Then интуитивно понятен. Рассмотрим элементы синтаксиса:

  • Given предоставляет контекст выполнения сценария тестирования, например, точки вызова сценария в приложении, а также любые необходимые данные.
  • When определяет набор операций, инициирующих тестирование, таких как действия пользователей или подсистем.
  • Then описывает ожидаемый результат тестирования.

В листинге 1 приведен тест входа в систему для простого Web-сайта. Пользователь выполняет вход на сайт и перенаправляется на страницу подтверждения входа.

Листинг 1. Исходный тест входа
Feature: Test login

Scenario Outline: Login Success and Failure
	Given I navigate to the mock application
	When I try to login with valid credentials
	Then I should see that I logged in successfully

Cucumber предоставляет возможность повторно использовать этот тест путем выбора значений из таблицы. Тест в листинге 1 можно легко преобразовать, добавив проверку успеха и неудачи входа, как показано в листинге 2.

Листинг 2. Проверка успеха или неудачи входа
@run
Feature: Test Login

Scenario Outline: Login Success and Failure
	Given I navigate to the mock application
	When I try to login with '<type>' credentials
	Then I should see that I logged in '<status>'
	
Examples:
	| type		| status		|
	| valid		| successfully		|
	| invalid	| unsuccessfully	|

Cucumber читает указанные файлы функций и выполняет тесты, используя указанные теги. Если, например, разместить листинг 2 в каталоге MockApp папки исходных тестов, его прочтет тестовый Java-класс, приведенный в листинге 3.

Листинг 3. Пример тестового Java-класса
@RunWith(Cucumber.class)
@Cucumber.Options(
        features = "MockApp",//путь к функциям
        format = {"json:target/integration_cucumber.json"},//средство разметки
        tags = {"@run"})//теги для включения(@)/исключения(@~)

public class RunTests {
}

В случае использования Maven необходимо добавить в POM-файл зависимости, приведенные в листинге 4.

Листинг 4. POM-файл Maven с зависимостями Cucumber
<dependency>
	<groupId>info.cukes</groupId>
	<artifactId>cucumber-core</artifactId>
	<version>${cucumber.version}</version>
</dependency>
<dependency>
	<groupId>info.cukes</groupId>
	<artifactId>cucumber-java</artifactId>
	<version>${cucumber.version}</version>
</dependency>
<dependency>
	<groupId>info.cukes</groupId>
	<artifactId>cucumber-junit</artifactId>
	<version>${cucumber.version}</version>
</dependency>

Интерпретация файлов функций

Обратите внимание, что мы пока не говорили о содержимом файлов функций. Для этого в дополнение к классу, созданному в листинге 3, нужно создать еще один класс. Например, класс, приведенный в листинге 5, будет интерпретировать файлы функций, созданные в листинге 2, и пошагово записывать операторы в журнал.

Листинг 5. Класс LoginSteps
public class LoginSteps {
	private static final Logger LOGGER = Logger.getLogger(LoginSteps.class.getName());
	
	@Given("^I navigate to the mock application$")
	public void given_I_navigate_to_the_mock_application(){
		LOGGER.info("Entering: I navigate to the mock application");
	}
	
	@When("^I try to login with '(.+)' credentials$")
	public void when_I_try_to_login(String credentialsType){
		LOGGER.info("Entering: I try to login with " + 
			credentialsType + " credentials");
	}
	
	@Then("^I should see that I logged in '(.+)'$")
	public void then_I_login(String outcome){
		LOGGER.info("Entering: I should see that I logged in " + outcome);
	}
}

Каждый метод имеет аннотации Given, When или Then, содержащие регулярные выражения, соответствующие строкам файла функций.

Попытка выполнить тест Cucumber ни к чему не приведет, поскольку отсутствует тестовый код, который мы напишем в следующем разделе.


Управление браузером с помощью Selenium

Имея написанные тесты, мы должны обеспечить возможность их выполнения в Web-браузере. Для этого мы используем Selenium, инфраструктуру автоматизации Web-браузера, хорошо сочетающуюся с Cucumber. Есть два способа управления браузером с помощью Selenium:

  1. Selenium-RC использует JavaScript для управления Web-страницей и работает внутри песочницы JavaScript.
  2. WebDriver использует встроенный механизм автоматизации, который работает быстрее и не так подвержен ошибкам, но поддерживает меньше браузеров.

Для тестирования демонстрационного приложения мы будем использовать WebDriver.

Запуск экземпляра браузера

Если для сборки приложения используется Maven, нужно добавить в POM-файл следующие зависимости:

<dependency>
	<groupId>org.seleniumhq.selenium</groupId>
	<artifactId>selenium-java</artifactId>
	<version>${selenium.version}</version>
</dependency>

Затем создается класс BrowserDriver с методами запуска и закрытия браузера (см. листинг 6).

Листинг 6. Класс BrowserDriver
private static WebDriver mDriver;
	
public synchronized static WebDriver getCurrentDriver() {
	if (mDriver==null) {
		try {
                	mDriver = new FirefoxDriver(new FirefoxProfile());
	        } finally{
	        	Runtime.getRuntime().addShutdownHook(
					new Thread(new BrowserCleanup()));
	        }
	}
	return mDriver;
}

private static class BrowserCleanup implements Runnable {
	public void run() {
		LOGGER.info("Closing the browser");
		close();
	}
}

public static void close() {
	try {
		getCurrentDriver().quit();
		mDriver = null;
		LOGGER.info("closing the browser");
	} catch (UnreachableBrowserException e) {
		LOGGER.info("cannot close browser: unreachable browser");
	}
}

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

Теперь нам необходимы методы для браузера, делающие что-нибудь полезное. В листинг 7 приведен метод для загрузки страницы, который добавляется в класс BrowserDriver из листинга 6.

Листинг 7. Загрузка страницы
public static void loadPage(String url){;
	LOGGER.info("Directing browser to:" + url);
	getCurrentDriver().get(url);
}

Подключение тестового кода к браузеру

Теперь нужно подключить к нашему тесту методы класса BrowserDriver. Создадим новый класс Navigation для управления тестами. Класс Navigation также делегирует задания контейнерам страниц, которые мы обсудим в следующем разделе.

Класс Navigation должен иметь методы для управления тестом, соответствующие методам в этом тесте. В листинге 8 приведен пример метода класса LoginSteps для загрузки Web-страницы (см. листинг 5).

Листинг 8. Методы класса LoginSteps в классе BrowserDriver
public void given_I_navigate_to_the_mock_application(){
	BrowserDriver.loadPage(
		"http://localhost/MockApplication/html/MockApplication.html");
}

Метод в листинге 8 используется для загрузки Web-страницы. Затем нужно добавить в класс LoginSteps вызов этого метода. Заменим существующий метод из листинга 5 методом из листинга 9.

Листинг 9. Новый метод класса LoginStep
	@Given("^I navigate to the mock application$")
	public void given_I_navigate_to_the_mock_application(){
		LOGGER.info("Entering: I navigate to the mock application");
		navigation.given_I_navigate_to_the_mock_application();
	}

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


Использование объектов страницы для RIA-приложения

Следующим шагом является подтверждение успешной загрузки Web-страницы. Для этого мы изменим традиционный шаблон Page Object (см. раздел Ресурсы), используемый для выполнения специфичных для страницы взаимодействий.

Объекты страницы (Page Object) используются для выделения взаимодействий между пользователем и Web-страницей в отдельный объект. Можно сказать, что такой объект предоставляет сервисы, которые предлагает Web-страница. Эти объекты должны уметь находить на странице DOM-элементы и взаимодействовать с ними. В нашем примере мы вызываем несколько классов представления (view) объекта страницы и выделяем DOM-ссылки в классы контейнера (container).

Большая разница между нашей реализацией и обычным способом работы с объектами страницы состоит в том, что отображается на странице. В традиционном Web-приложении каждый запрос к серверу возвращает новую страницу. Таким образом, объектом страницы является вся Web-страница. В современных одностраничных Web-приложениях возвращается несколько страниц со скрытыми и отображаемыми секциями. В одностраничном приложении нет смысла представлять всю Web-страницу в виде объекта страницы; наш объект страницы представляет собой автономную секцию страницы.

Секциями в нашем примере приложения являются представления Login View и Home View. Хотя наше приложение отображает только одну секцию за раз, более крупные приложение могут отображать несколько секций одновременно. Поскольку после завершения запроса к серверу новая страница не возвращается, определить завершение запроса непросто. Например, если пользователь входит в систему с неверными учетными данными, на экране отобразится ошибка. Чтобы определить (и соответственно протестировать) завершение запроса, придется выполнить опрос об отображении ошибки или истечении установленного времени.

Поиск DOM-элементов в представлении

Рассмотрим код реализации. Прежде всего мы создаем класс контейнера LoginContainer. Этот класс используется для поиска DOM-элементов представления Login View. Для поиска DOM-элементов используется аннотация @FindBy, которая принимает параметры, определяющие, что нужно найти. В листинге 10 мы используем параметр How в качестве переменной поиска. Опциями параметра How являются CSS, ID и XPATH.

Листинг 10. Класс LoginContainer с операторами поиска DOM-элементов
	@FindBy(how = How.ID, using = "LoginPage")
	public WebElement loginPageDiv;
	
	@FindBy(how = How.CSS, using = "#LoginPage input[name=username]")
	public WebElement usernameInput;
	
	@FindBy(how = How.CSS, using = "#LoginPage input[name=password]")
	public WebElement passwordInput;
	
	@FindBy(how = How.CSS, using = "#LoginPage span[role='button']")
	public WebElement submitButton;

Затем мы создаем класс LoginPage для конкретных взаимодействий со страницей входа тестируемого приложения.

При загрузке в браузере нашего сайта нужно проверить, отображается ли страница входа; для этого мы просто редактируем метод given_I_navigate_to_the_mock_application() класса Navigation, чтобы вызвать метод isDisplayedCheck() в новом классе LoginView (см. листинг 11).

Листинг 11. Проверка отображения страницы входа в браузере
	public static void isDisplayedCheck(){
		LOGGER.info("Checking login page is displayed");
		BrowserDriver.waitForElement(loginContainer.loginPageDiv);
		loginContainer.loginPageDiv.isDisplayed();
	}

Итак, мы проверили отображение в браузере страницы входа нашего сайта – это наш первый сценарий в файле функций. Теперь нужно протестировать вход.


Вход с использованием учетных данных

Согласно файлу функций в листинге 2, на следующем этапе тестирования нужно посмотреть, что происходит, когда пользователь выполняет вход с использованием учетных данных <type>. В данном случае type (тип) означает один из возможных вариантов, которые мы свели к valid или invalid.

В Cucumber можно перейти от строкового типа к перечислению, но этот подход имеет ограничения. Например, чтобы correct и valid означали одно и то же, нужно использовать отдельные экземпляры перечислений. Другим вариантом является поиск с использованием массива Strings в качестве аргумента для перечисления. Размещение такого метода поиска в перечислении в листинге 12 позволяет иметь одно значение для нескольких строк.

Листинг 12. Перечисление CredentialsType
public enum CredentialsType {

   VALID(new String[]{"valid", "correct"}),
   INVALID(new String[]{"invalid"});
	
   private String[] aliases;
	
   private CredentialsType(String[] aliases){
        this.aliases = aliases;
   }

   public static CredentialsType credentialsTypeForName(String credentialsType) 
		throws IllegalArgumentException{
	for(CredentialsType ct: values()){
		for(String alias: ct.aliases){
			if(alias.equalsIgnoreCase(credentialsType)){
				return ct;
			}
		}
	}
	throw credentialsTypeNotFound(credentialsType);
    }

    private static IllegalArgumentException credentialsTypeNotFound(String ct) {
        return new IllegalArgumentException(("Invalid credentials type [" + ct + "]"));
    }
}

Теперь мы создадим пользователя указанного типа. Мы реализуем пользователя в виде конечного автомата теста (см. раздел Ресурсы), поскольку учетные данные пользователя скорее всего будут использоваться неоднократно. Например, может потребоваться проверка отображения имени пользователя после его входа в систему. Реализация фабрики пользователей более эффективна, чем жесткое кодирование данных отдельного пользователя, т.е. размещение этих данных в нескольких местах теста. Тестовый пользователь и фабрика пользователей приведены в листинге 13.

Листинг 13. Тестовый пользователь и фабрика пользователей
public class User {
	private String username;
	private String password;
	
	public User withUserName(String username){
		this.username = username;
		return this;
	}
	
	public String getUsername(){
		return username;
	}
	
	public User withPassword(String password){
		this.password = password;
		return this;
	}
	
	public String getPassword(){
		return password;
	}
	
}

public class Users {
	public static User createValidUser(){
		User user = new User();
		user.withUserName("username").withPassword("password");
		return user;
	}
	
	public static User createInvalidUser(){
		User user = new User();
		user.withUserName(").withPassword(");
		return user;
	}
}

Теперь добавим в класс Navigation метод, приведенный в листинге 14, и изменим вызывающий его метод в классе LoginSteps.

Листинг 14. Метод login для класса Navigation
private User user;

public void when_I_try_to_login(String credentialsType) {
	CredentialsType ct = CredentialsType.credentialsTypeForName(credentialsType);
	switch(ct){
		case VALID:
			//создание пользователя типа valid (допустимый)
			user = Users.createValidUser();
		break;
		case INVALID:
			//создание пользователя типа invalid (недопустимый)
			user = Users.createInvalidUser();
		break;
	}
	//попытка входа
	LoginView.login(user.getUsername(), user.getPassword());
}

На последнем шаге мы создадим метод login в классе LoginView (см. листинг 15). Этот метод использует ранее созданный loginContainer (см. листинг 10), который указывает, как найти соответствующие DOM-элементы. Обратите внимание, что в обертках Selenium для этих элементов есть несколько полезных методов, позволяющих взаимодействовать с ними. Нам нужны два метода SendKeys для ввода имени пользователя и пароля в соответствующие поля и нажатия кнопки отправки учетных данных.

Листинг 15. Метод login для класса LoginView
public static void login(String username, String password){
	LOGGER.info("Logging in with username:"+username+" password:"+password);
	loginContainer.usernameInput.sendKeys(username);
	loginContainer.passwordInput.sendKeys(password);
	loginContainer.submitButton.click();
	LOGGER.info("Login submitted");
}

Запустив тест, вы увидите, как в соответствующие поля вводятся имя пользователя и пароль, а затем нажимается кнопка Submit. Вы можете загрузить полный исходный код реализации, прилагаемый к данной статье.


Тестирование в разных браузерах

До сих пор мы выполняли контрольные тесты только в Web-браузере Firefox, который вместе с браузерами Opera, Safari и Internet Explorer поддерживается драйвером Selenium WebDriver. Выполнив небольшую дополнительную работу, можно запускать контрольные тесты в браузерах Chrome, iOS, Android и Opera Mobile.

Наш опыт показывает, что можно относительно легко переключаться между браузерами, передавая системное свойство во время исполнения, например -Dbrowser=safari. Это системное свойство может быть прочитано в тестах с помощью кода, приведенного в листинге 16.

Листинг 16. Указание тестового браузера
Browsers browser;
WebDriver driver;
		
if(System.getProperty(BROWSER_PROP_KEY)==null){
	browser = Browsers.FIREFOX;
}else{
	browser=Browsers.browserForName(System.getProperty(BROWSER_PROP_KEY));
}
switch(browser){
	case CHROME:
		System.setProperty("webdriver.chrome.driver", 
"src/main/resources/chromedriver");
		driver = new ChromeDriver();
		break;
	case SAFARI:
		driver = new SafariDriver();
		break;
	case FIREFOX:
		default:
		driver = new FirefoxDriver();
		break;
}

Динамические тестовые данные

Сопровождение тестовых данных является одной из самых больших проблем автоматизированного тестирования. При переносе теста в новую среду не хочется настраивать все тестовые данные вручную, а при изменении данных не хочется менять их для каждого теста. Одним из способов обойти эту проблему является динамическое создание данных в начале тестирования путем обращения теста к соответствующим базам данных или Web-сервисам.

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

Для выполнения тестов в Chrome необходимо вручную загрузить драйвер Chrome и указать в системном свойстве webdriver.chrome.driver местоположение этого драйвера (см. листинг 16).


Тестирование и среда сборки

Возможность локального выполнения тестов не очень полезна, если их нельзя подключить к сборке. Мы продемонстрируем использование Selenium Grid (см. раздел Ресурсы) для одновременного выполнения нескольких тестов на машине сборки.

Начнем с установки Selenium Grid на тестовой машине. Затем передадим системное свойство -Dremote=true, что даст возможность переключать тесты с выполнения на одном локальном браузере на выполнение в сети.

Теперь нужно всего лишь обновить драйвер браузера. Предварительно мы создали один локальный Web-драйвер Firefox, используя код, приведенный в листинге 17.

Листинг 17. Указание Firefox в качестве тестового браузера
case FIREFOX:
	driver = new FirefoxDriver();
	break;

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

Листинг 18. Указание удаленного тестового браузера
case FIREFOX:
	String isRemote = System.getProperty("remote");
	if("true".equalsIgnoreCase(isRemote);{
		DesiredCapabilities firefox = DesiredCapabilities.firefox();
           firefox.setVersion("17");
           firefox.setPlatform(Platform.ANY);
           driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), firefox);
	else{
		driver = new FirefoxDriver();
	}
	break;

URL-адрес в листинге 18 – это адрес хаба (центрального сервера) Selenium Grid.

Выполнение наборов тестов

После развертывания сборку нужно протестировать. Одним из вариантов является запуск всех тестов в рамках одного большого набора. Однако по мере накопления тестов может оказаться, что выполнение такого набора требует слишком много времени. Альтернативой может быть пакетирование тестов в небольшие наборы с самого начала. Для группирования тестов можно использовать различные теги аннотаций в верхней части файлов функций. Например, для включения всех тестов входа в единый пакет используется тег @login. Затем для каждого пакета нужно создать соответствующий Java-класс (см. листинг 19).

Листинг 19. Выполнение пакета тестов
@RunWith(Cucumber.class)
@Cucumber.Options(
        features = "MockApp",//path to the features
        format = {"json:target/integration_cucumber.json"},//what formatters to use
        tags = {"@login"})//what tags to include(@)/exclude(@~)
public class RunTests {
}

Заключение

Создание автоматизированной инфраструктуры для тестирования Web-приложений является насущной и важной в долгосрочной перспективе задачей. Использование инструментов Selenium и Cucumber упрощает эту задачу и позволяет создавать настраиваемые наборы тестов. Данная статья посвящена использованию Selenium и Cucumber для создания набора автоматизированных тестов для RIA-приложения, а также представляет краткое введение в файлы функций и советы по тестированию кода приложения в различных браузерах. Перспективное планирование в следующих областях может вознаградить ваши усилия в будущем:

  • Применение тестовых данных в нескольких средах является болевой точкой автоматизации тестирования. Подключение инфраструктуры автоматизации тестирования к базам данных или Web-сервисам позволяет контрольным тестам динамически получать необходимые данные перед запуском.
  • Интерпретатор файла функций (см. листинг 5) может быстро превратиться в очень большой и замусоренный файл. Тщательно документируйте шаги по созданию новых тестов, и вам не придется копаться в тысячах строк тестового кода, когда что-то пойдет не так.
  • Выполнение тестов может потребовать довольно много времени, особенно для нескольких браузеров. Планируйте количество браузеров (и, возможно, машин, хотя несколько браузеров могут работать на одной машине), подключаемых к Selenium Grid, чтобы тесты выполнялись за разумное время.

Загрузка

ОписаниеИмяРазмер
Пример кодаa-automating-ria-src.zip10МБ

Ресурсы

Научиться

Получить продукты и технологии

  • Cucumber: написание тестов в обычном текстовом формате и преобразование их в Java-код.
  • Selenium: инструмент автоматизации тестирования, совместимый с большинством мобильных и Web-браузеров.
  • Selenium Grid: распределение автоматизированных тестов между несколькими браузерами.

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



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

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=957576
ArticleTitle=Автоматизированное тестирование с помощью Selenium и Cucumber
publish-date=12162013