- Запустил hub c selenium grid.
- Запустил два экземпляра appium, запустил два эмулятора Genimotion
- В консоли грида вижу оба эмулятора.
Запускаю тесты.
Ожидаю: Тесты будут прогоняться на двух девайсах
Реально: Тесты запускаются на одном девайсе.
Вопрос:
Как правильно передать в capabilities несколько устройств чтобы все тесты прогонялись на всех подключенных девайсах?
Вам следует гдето задать количество тредов для junit. В тестНГ есть возможность указывать количество тредов, возможно в jUnit стото подобное есть. Так что это не проблема капабилитис аппиума, это сам junit нужно копать
В pom файле в настройках maven-surefire-plugin я указал:
<parallel>methods</parallel>
<threadCount>2</threadCount>
Но этого видимо мало.
Можно увидеть ваш pom.xml ?
4.0.0
<groupId>ru.company</groupId>
<artifactId>project-android</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java-language.level>1.8</java-language.level>
<io.appium.version>6.1.0</io.appium.version>
<junit.version>4.12</junit.version>
<properties.loader.version>1.6</properties.loader.version>
<allure.junit.adaptor.version>1.5.0.RC2</allure.junit.adaptor.version>
<allure.maven.plugin.version>2.5</allure.maven.plugin.version>
<aspectj.version>1.8.11</aspectj.version>
<log4j.version>2.11.2</log4j.version>
<gson.version>2.8.0</gson.version>
<assertj.version>3.11.1</assertj.version>
<maven-shade-plugin.version>2.4.3</maven-shade-plugin.version>
<maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
</properties>
<repositories>
<repository>
<id>company-maven</id>
<url>http://url.ru</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>${io.appium.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.properties</groupId>
<artifactId>properties-loader</artifactId>
<version>${properties.loader.version}</version>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<version>${allure.junit.adaptor.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<parallel>methods</parallel>
<threadCount>2</threadCount>
<runOrder>alphabetical</runOrder>
<testFailureIgnore>false</testFailureIgnore>
<argLine>
-Dfile.encoding=UTF-8
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<properties>
<property>
<name>listener</name>
<value>ru.yandex.qatools.allure.junit.AllureRunListener</value>
</property>
</properties>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java-language.level}</source>
<target>${java-language.level}</target>
</configuration>
</plugin>
</plugins>
</build>
Также в консоли грида вижу:
3 requests waiting for a slot to be free.
и указаны Capabilities для второго девайса, но он не используется совсем, весь прогон идет на первом девайсе
Тесты запускаю через команду
mvn -T 2 test -Dtest=TestClass
А как вы сейчас задаете капабилитис для аппиум драйвера ? И как стартуете драйвер? Можно увидеть код ?
Сейчас пробую аппиумы из консоли запускать сразу передавая им device-name:
appium --nodeconfig C:\selenium-nodes\nodes_config_device_1.json -p 4723 --device-name 1.1.1.1:5555
appium --nodeconfig C:\selenium-nodes\nodes_config_device_2.json -p 4724 --device-name 1.1.1.2:5555
(тут значение device-name для примера)
В коде пока не знаю как задать чтобы несколько девайсов передавать в deviceName.
Создание драйвера:
public class DriverProvider {
private SettingsPropLoader settingsLoader = new SettingsPropLoader();
public AndroidDriver prepareDriver(boolean withReset) {
return prepare(withReset);
}
private AndroidDriver prepare(boolean withReset) {
AndroidDriver driver = null;
DesiredCapabilities capabilities = new DesiredCapabilities();
if (!withReset) {
capabilities.setCapability(“noReset”, true);
capabilities.setCapability(“fullReset”, false);
}
String gridUrl = “http://0.0.0.0:4444/wd/hub”;
capabilities.setCapability(“app”, settingsLoader.getTestAppPath());
capabilities.setCapability(“appPackage”, settingsLoader.getAppPackage());
capabilities.setCapability(“appActivity”, settingsLoader.getAppActivity());
capabilities.setCapability(“automationName”, settingsLoader.getAutomationName());
capabilities.setCapability(“platformName”, settingsLoader.getPlatformName());
try {
driver = new AndroidDriver(new URL(gridUrl), capabilities);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return driver;
}
}
Базовый класс:
public class BaseTest {
protected static AndroidDriver driver;
@Before
public void setUp() {
launchApp(true);
}
protected void launchApp(boolean withReset) {
driver = new DriverProvider().prepareDriver(withReset);
}
@After
public void tearDown() {
driver.quit();
}
}
Хмм… пока единственное что могу сказать что если вы хотите в паралелизацию то статик для драйвера нужно убирать
protected static AndroidDriver driver;
Возможно в этом кстати и кроется проблема. У вас, к примеру, 2 теста, а в случае статик static AndroidDriver driver драйвер один, т.е. оба теста ссылаются на один драйвер.
Также для пробега тестов в нескольких тредах, драйвер вообще должен быть ThreadLocal
посмотрите сдесь неплохо описано
https://www.swtestacademy.com/appium-parallel-tests/
Все сделал, но пока результат тот же.
Если идейно только Grid - добавьте в строку запуска UDID каждого девайса. Кроме того для гибридных приложений нужно указать 3 порта (android server, native agent, web agent).
пример: appium -a localhost -p 4730 -bp 4720 --chromedriver-port 8400 --nodeconfig /path/to/device/config.json --default-capabilities ‘{“udid”:“DSFasfs32434”}’
Для каждого инстанса appium server p/bp/chromedriver-port/nodeconfig/default-capabilities должы быть уникальнийми (порты не заняты другими сервисами).
Если не указать udid - каждый appium server возьмет первый девайс/емулятор в списке от adb devices
.
На своем проекте я использую GitHub - ochubey/device-dealer: Device management service that helps you to run Appium tests in parallel with real devices in your local lab.. Там автоматизирована вся рутина, а мне будет приятно если решение поможет не только мне
Спасибо вам.
Моя проблема была в том что думал device-name достаточно указать, но udid был и правда необходим.
Запускаю аппиум так:
appium --nodeconfig C:\selenium-nodes\nodes_config_device_1.json -p 4723 --device-name Device_1 --udid 1.1.1.1:5555
appium --nodeconfig C:\selenium-nodes\nodes_config_device_2.json -p 4724 --device-name Device_2 --udid 1.1.1.2:5555
и все заработало.
Мне бы конечно параметры device-name и udid куда нибудь в файл вынести и оттуда читать…
То есть прямо в коде где я задаю
capabilities.setCapability(“app”, settingsLoader.getTestAppPath());
capabilities.setCapability(“appPackage”, settingsLoader.getAppPackage());
capabilities.setCapability(“appActivity”, settingsLoader.getAppActivity());
capabilities.setCapability(“automationName”, settingsLoader.getAutomationName());
capabilities.setCapability(“platformName”, settingsLoader.getPlatformName());
но не могу понять как подавать например в deviceName
, так как там два значения, в отличие например от platformName
Вам обязательно контролировать какой тест на каком девайсе запускать?
Если нет (тоесть тест не зависит от названия девайса/версии) то есть следующий трюк:
{
"capabilities": [
{
"applicationName": "android",
"platformName": "android",
"maxInstances": 1,
"udid": "0815f85ce2103703",
"platformVersion": "5.1.1",
"platform": "MAC"
}
],
"configuration": {
"cleanUpCycle": 2000,
"host": "127.0.0.1",
"hubHost": "127.0.0.1",
"hubPort": 4444,
"maxSession": 1,
"port": 53251,
"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
"register": true,
"registerCycle": 5000,
"timeout": 30000
}
}
А в капабилитях добавить
capabilities.setCapability(“applicationName”, “android”);
capabilities.setCapability(“deviceName”, “android”);
UPD: ошибка на скринах, обновил JSON