Вопрос по поводу многопоточной передачи данных DataProvider
Я пытаюсь достичь параллелизма в новой многопоточной тестовой среде, которую я пишу. У меня есть класс DataProviderManager.java, который содержит мой статический DataProvider
@DataProvider(parallel = true, name = Config.StaticProps.DEFAULT_WEB_DATA_PROVIDER)
public static Object[][] defaultWebDataProvider() {
return new Object[][] {
new Object[]{"chrome", "69", "MAC 10.12"},
new Object[]{"safari", "11.0", "Mac 10.13"},
new Object[]{"safari", "11.0", "Mac 10.13"}
new Object[]{"chrome", "70", "Mac 10.13"}
new Object[]{"firefox", "63", "MAC 10.12"},
new Object[]{"firefox", "62", "MAC 10.12"}
};
}
У меня есть тестовый класс, который передает 3 параметра из моего DataProvider в геттеры и сеттеры ThreadLocal, чтобы установить Selenium Capabilities для каждого потока, создающего экземпляр драйвера с этими возможностями. Сам тест просто открывает определенный URL на основе некоторых параметров времени выполнения.
@Factory(dataProvider = StaticProps.DEFAULT_WEB_DATA_PROVIDER, dataProviderClass = DataProviderManager.class)
//@Factory(dataProvider = StaticProps.DEFAULT_WEB_DATA_PROVIDER)
public WebExampleTest(String browser, String browserVersion, String platform) {
super.setRunParams(browser, browserVersion, platform);
}
@BeforeMethod(alwaysRun = true)
public void setupTest() {
home = new Home();
}
@TestCaseId("")
@Features({GroupProps.WEB})
@Test(groups = {GroupProps.DEBUG}, dataProvider = StaticProps.DEFAULT_WEB_DATA_PROVIDER, dataProviderClass = DataProviderManager.class)
@Parameters({ ParamProps.WEB, ParamProps.MOBILE_WEB })
public void openSiteTest(String browser, String browserVersion, String platform) {
Logger.logMessage("Current Thread ID: " + Thread.currentThread().getId());
new WebInteract(null, null).pause(1000).openUrl(URLBuilder.buildUrl());
}
Вот мой файл testing.xml
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Test Engineering Core Suite"
parallel="true"
data-provider-thread-count="6"
thread-count="6"
verbose="2">
<!-- LISTENERS -->
<listeners>
<listener class-name="com.msg.test.core.listeners.TestListeners" />
<listener class-name="com.msg.test.core.listeners.SuiteListeners" />
<listener class-name="com.msg.test.core.listeners.TestAnnotationTransformer" />
</listeners>
<!-- TEST EXECUTION QUEUE -->
<test verbose="1" name="All Tests" annotations="JDK">
<!-- TEST GROUPS
"Full" - all tests in the test suite.
"Broken" - those tests that are broken and safe to ignore until they can be resolved.
-->
<!--<groups>-->
<!--<run>-->
<!--<include name="Debug" />-->
<!--<exclude name="Broken" />-->
<!--</run>-->
<!--</groups>-->
</test>
</suite>
Вот часть вывода, чтобы показать вам, что происходит в настоящее время
2018-11-18 12:49:37.633 ========NEW TEST SESSION========
2018-11-18 12:49:37.633 Desktop OS: Mac 10.13
2018-11-18 12:49:37.633 Browser: chrome
2018-11-18 12:49:37.633 Browser Version: 70
2018-11-18 12:49:37.634 Current Thread ID: 66
2018-11-18 12:49:37.635 Pause for '1000' milliseconds.
Nov 18, 2018 12:49:37 AM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
2018-11-18 12:49:37.846 Session ID: 622fda273344469ab98aef0d06f90315
2018-11-18 12:49:37.847 ========NEW TEST SESSION========
2018-11-18 12:49:37.847 Desktop OS: Mac 10.13
2018-11-18 12:49:37.847 Browser: chrome
2018-11-18 12:49:37.848 Browser Version: 70
2018-11-18 12:49:37.849 Current Thread ID: 68
2018-11-18 12:49:37.849 Pause for '1000' milliseconds.
2018-11-18 12:49:37.950 Open url 'https://www.example.com'.
2018-11-18 12:49:38.571 Open url 'https://www.example.com'.
2018-11-18 12:49:38.571 Open url 'https://www.example.com'.
2018-11-18 12:49:38.576 ======SUCCESS======
2018-11-18 12:49:38.577 Desktop OS: Mac 10.13
2018-11-18 12:49:38.577 Browser: chrome
2018-11-18 12:49:38.577 Browser Version: 70
2018-11-18 12:49:38.640 Open url 'https://www.example.com'.
2018-11-18 12:49:38.854 Open url 'https://www.example.com'.
2018-11-18 12:49:39.059 ======SUCCESS======
2018-11-18 12:49:39.060 Desktop OS: Mac 10.13
2018-11-18 12:49:39.060 Browser: chrome
2018-11-18 12:49:39.060 Browser Version: 70
2018-11-18 12:49:39.083 ======SUCCESS======
2018-11-18 12:49:39.084 Desktop OS: Mac 10.13
2018-11-18 12:49:39.084 Browser: chrome
2018-11-18 12:49:39.084 Browser Version: 70
2018-11-18 12:49:39.126 ======SUCCESS======
2018-11-18 12:49:39.126 Browser: chrome
2018-11-18 12:49:39.126 Browser Version: 70
2018-11-18 12:49:39.393 ======SUCCESS======
Как вы можете видеть, я могу выполнять один и тот же тест параллельно в разных потоках, но каждый поток выполняется в одном браузере, версии и платформе из моего DataProvider.
Мой вопрос заключается в том, чтобы вместо запуска нескольких потоков, каждый из которых выполнял одни и те же данные (браузер, платформа версий - chrome, 70, Mac 10.13) из DataProvider одновременно, как запустить каждый из них (браузер, версия, платформа)?
new Object[]{"chrome", "69", "MAC 10.12"}, **This should be thread 1**
new Object[]{"safari", "11.0", "Mac 10.13"}, **This should be thread 2**
new Object[]{"safari", "11.0", "Mac 10.13"} **This should be thread 3**
new Object[]{"chrome", "70", "Mac 10.13"} **This should be thread 4**
new Object[]{"firefox", "63", "MAC 10.12"}, **This should be thread 5**
new Object[]{"firefox", "62", "MAC 10.12"} **This should be thread 6**
от DataProvider на разных потоках одновременно?
1 ответ
Вот как работает TestNG
Обычный @Test
метод в сочетании с поставщиком данных
Когда нормальный @Test
Аннотированный метод тестирования необходимо запускать несколько раз, но с разными наборами данных вы связываете его с поставщиком данных. Чтобы запустить его параллельно, вы в основном включаете параллельный атрибут на @DataProvider
аннотацию и укажите атрибут parallel=methods
на <suite>
уровень тега.
Ниже приведен пример, который показывает все это в действии. Это использует org.testng.IHookable
интерфейс, так что можно в основном извлечь параметры, которые отправляются на @Test
метод с помощью поставщика данных и использовать их для выполнения любой настройки, необходимой для каждой итерации.
Вы могли бы использовать @BeforeMethod
аннотации, но невозможно извлечь параметры, отправленные в @Test
метод поставщиком данных, изнутри @BeforeMethod
,
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestClassWithDataDrivenTest implements IHookable {
@Override
public void run(IHookCallBack callBack, ITestResult result) {
beforeMethod(callBack.getParameters());
callBack.runTestMethod(result);
}
public void beforeMethod(Object[] parameters) {
String browser = parameters[0].toString();
String browserVersion = parameters[1].toString();
String platform = parameters[2].toString();
String msg =
String.format(
"[beforeMethod()-Thread Id : %d] [%s] flavor version [%s] on platform [%s]",
Thread.currentThread().getId(), browser, browserVersion, platform);
System.err.println(msg);
}
@Test(dataProvider = "dp")
public void testMethod(String browser, String browserVersion, String platform) {
String msg =
String.format(
"[testMethod()-Thread Id : %d] [%s] flavor version [%s] on platform [%s]",
Thread.currentThread().getId(), browser, browserVersion, platform);
System.err.println(msg);
}
@DataProvider(parallel = true, name = "dp")
public static Object[][] defaultWebDataProvider() {
return new Object[][] {
new Object[] {"chrome", "69", "MAC 10.12"},
new Object[] {"safari", "11.0", "Mac 10.13"},
new Object[] {"safari", "11.0", "Mac 10.13"},
new Object[] {"chrome", "70", "Mac 10.13"},
new Object[] {"firefox", "63", "MAC 10.12"},
new Object[] {"firefox", "62", "MAC 10.12"}
};
}
}
Соответствующий вывод при запуске этого теста, как показано ниже
[beforeMethod()-Thread Id : 11] [chrome] flavor version [69] on platform [MAC 10.12]
[beforeMethod()-Thread Id : 12] [safari] flavor version [11.0] on platform [Mac 10.13]
[beforeMethod()-Thread Id : 14] [chrome] flavor version [70] on platform [Mac 10.13]
[beforeMethod()-Thread Id : 13] [safari] flavor version [11.0] on platform [Mac 10.13]
[beforeMethod()-Thread Id : 15] [firefox] flavor version [63] on platform [MAC 10.12]
[testMethod()-Thread Id : 12] [safari] flavor version [11.0] on platform [Mac 10.13]
[beforeMethod()-Thread Id : 16] [firefox] flavor version [62] on platform [MAC 10.12]
[testMethod()-Thread Id : 13] [safari] flavor version [11.0] on platform [Mac 10.13]
[testMethod()-Thread Id : 14] [chrome] flavor version [70] on platform [Mac 10.13]
[testMethod()-Thread Id : 11] [chrome] flavor version [69] on platform [MAC 10.12]
[testMethod()-Thread Id : 16] [firefox] flavor version [62] on platform [MAC 10.12]
[testMethod()-Thread Id : 15] [firefox] flavor version [63] on platform [MAC 10.12]
===============================================
Default Suite
Total tests run: 6, Passes: 6, Failures: 0, Skips: 0
===============================================
@Factory
в сочетании с поставщиком данных
Один использует @Factory
метод (эта аннотация может быть добавлена поверх конструктора или статического метода, который возвращает Object[]
) когда нужно создать экземпляры тестового класса.
Экземпляр тестового класса определяется как обычный класс, в котором находится один или несколько @Test
методы в нем. Фабрика в сочетании с поставщиком данных использует данные, предоставленные поставщиком данных, для создания экземпляров каждого класса тестирования.
Если вы хотите, чтобы TestNG запустил @Test
методы во всех экземплярах параллельно одним выстрелом (TestNG по-прежнему будет запускать все @Test
методы в каждом из тестовых классов в последовательном порядке), затем вы можете указать его через атрибут parallel=instances
на <suite>
тег.
Обратите внимание, что вы не можете запустить все @Test
методы в каждом из экземпляров тестового класса параллельно. TestNG AFAIK не имеет возможности включить параллелизм на этом уровне.
Ниже приведен пример, который показывает это в действии
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class TestClassWithFactory {
private String browser, browserVersion, platform;
@Factory(dataProvider = "dp")
public TestClassWithFactory(String browser, String browserVersion, String platform) {
this.browser = browser;
this.browserVersion = browserVersion;
this.platform = platform;
}
@BeforeMethod
public void beforeMethod() {
String msg =
String.format(
"[Instance id %d][beforeMethod()-Thread Id : %d] [%s] flavor version [%s] on platform [%s]",
this.hashCode(), Thread.currentThread().getId(), browser, browserVersion, platform);
System.err.println(msg);
}
@Test
public void testMethod() {
String msg =
String.format(
"[Instance id %d][testMethod()-Thread Id : %d] [%s] flavor version [%s] on platform [%s]",
this.hashCode(), Thread.currentThread().getId(), browser, browserVersion, platform);
System.err.println(msg);
}
@DataProvider(parallel = true, name = "dp")
public static Object[][] defaultWebDataProvider() {
return new Object[][] {
new Object[] {"chrome", "69", "MAC 10.12"},
new Object[] {"safari", "11.0", "Mac 10.13"},
new Object[] {"safari", "11.0", "Mac 10.13"},
new Object[] {"chrome", "70", "Mac 10.13"},
new Object[] {"firefox", "63", "MAC 10.12"},
new Object[] {"firefox", "62", "MAC 10.12"}
};
}
}
XML-файл комплекта testng, как показано ниже
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="53345934_suite" parallel="instances" verbose="2">
<test name="53345934_test">
<classes>
<class name="com.rationaleemotions.stackru.qn53345934.TestClassWithFactory"/>
</classes>
</test>
</suite>
Результат выполнения такой, как показано ниже:
...
... TestNG 7.0.0-beta1 by Cédric Beust (cedric@beust.com)
...
[Instance id 1627821297][beforeMethod()-Thread Id : 15] [safari] flavor version [11.0] on platform [Mac 10.13]
[Instance id 1549409129][beforeMethod()-Thread Id : 14] [chrome] flavor version [70] on platform [Mac 10.13]
[Instance id 922872566][beforeMethod()-Thread Id : 11] [firefox] flavor version [63] on platform [MAC 10.12]
[Instance id 1132547352][beforeMethod()-Thread Id : 12] [safari] flavor version [11.0] on platform [Mac 10.13]
[Instance id 1525037790][beforeMethod()-Thread Id : 13] [chrome] flavor version [69] on platform [MAC 10.12]
[Instance id 1132547352][testMethod()-Thread Id : 12] [safari] flavor version [11.0] on platform [Mac 10.13]
[Instance id 1549409129][testMethod()-Thread Id : 14] [chrome] flavor version [70] on platform [Mac 10.13]
[Instance id 1525037790][testMethod()-Thread Id : 13] [chrome] flavor version [69] on platform [MAC 10.12]
[Instance id 922872566][testMethod()-Thread Id : 11] [firefox] flavor version [63] on platform [MAC 10.12]
[Instance id 1627821297][testMethod()-Thread Id : 15] [safari] flavor version [11.0] on platform [Mac 10.13]
[Instance id 1651855867][beforeMethod()-Thread Id : 12] [firefox] flavor version [62] on platform [MAC 10.12]
[Instance id 1651855867][testMethod()-Thread Id : 12] [firefox] flavor version [62] on platform [MAC 10.12]
PASSED: testMethod
PASSED: testMethod
PASSED: testMethod
PASSED: testMethod
PASSED: testMethod
PASSED: testMethod
===============================================
53345934_test
Tests run: 6, Failures: 0, Skips: 0
===============================================
===============================================
53345934_suite
Total tests run: 6, Passes: 6, Failures: 0, Skips: 0
===============================================