DataProvider parallel text input - multithreading issue - java

I want to realize parallel test run with DataProvider for testing an input field.
Expected Result:
Parallel tests for each text in DataProvider
Open page
Write "Text1" (or "Text2" or "Text3")
Press "Search" button
Actual Result:
One test with every strings in DataProvider as one
Open page
Write "Text1Text2Text3" (why so?)
Press "Search" button
How I can solve this problem where every string in DataProvider inputing into the field?
Here is my code bellow.
TestNG.xml:
<suite name="TestParallel" parallel="tests" thread-count="2" data-provider-thread-count="2" preserve-order="false" >
<test name="ChromeTest">
<parameter name="browser" value="Chrome" />
<classes>
<class name="com.test.DataProviderTestParallel"/>
</classes>
</test>
<test name="FirefoxTest">
<parameter name="browser" value="Firefox" />
<classes>
<class name="com.test.DataProviderTestParallel"/>
</classes>
</test>
<test name="EdgeTest">
<parameter name="browser" value="Edge" />
<classes>
<class name="com.test.DataProviderTestParallel"/>
</class>
</classes>
</test>
</suite>
Test:
#BeforeTest
#Parameters("browser")
public static void initSelenium(String browser) throws Exception {
// Check if parameter passed from TestNG is 'firefox'
if(browser.equalsIgnoreCase("firefox")){
// Create firefox instance
FirefoxDriverManager.getInstance().setup();
driver = new FirefoxDriver();
}
// Check if parameter passed as 'chrome'
else if(browser.equalsIgnoreCase("chrome")){
ChromeDriverManager.getInstance().setup();
driver = new ChromeDriver();
}
// Check if parameter passed as 'Edge'
else if(browser.equalsIgnoreCase("Edge")){
EdgeDriverManager.getInstance().setup();
driver = new EdgeDriver();
}
else{
// If no browser passed throw exception
throw new Exception("Browser is not correct");
}
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
#DataProvider(name = "forSearch", parallel = true)
public Object[] forSearch() {
return new Object[]{
"Text1",
"Text2",
"Text3"
};
}
#Test(description = "Search text", dataProvider = "forSearch")
public void searchWithButton(String searchText) {
SupportPageObject supportPage = new SupportPageObject();
SearchResultPageObject searchResultPage = new SearchResultPageObject();
supportPage.open();
supportPage.isOpen();
// Input text into field
supportPage.writeQuestion(searchText);
// Press "search" button
supportPage.searchWithButton();
searchResultPage.isOpen();
}
UPD: I've found that this issue reproducing when i have data-provider-thread-count is bigger than 1.
In that case it opens thread-count number of windows and then on the last one input data-provider-thread-count times text from DataProvider.
But still has no idea how to fix it and enter the DataProvider text into each opened window separately.

You need to return an Object[][].
#DataProvider(name = "forSearch", parallel = true)
public Object[][] forSearch() {
return new Object[][]{
new Object[] { "Text1"},
new Object[] { "Text2"},
new Object[] { "Text3"}
};
}

Related

TestNG: Test Method In Second Class of Test Suite Being Called Only Once

I have two test methods in different classes. The first method, let's say "createCustomer" is using dataProvider to get the inputs from an excel file and creates three customers.
#Test(dataProvider = "createCustomerTestData", dataProviderClass = createCustomerDataProvider.class)
public void addStockAccountWithAllInput(ITestContext context) throws JsonProcessingException {
//Rest-Assured code goes here
ISuite suite = context.getSuite();
suite.setAttribute("customerID", js.get("customerID"));
}
The second method, let's say "getCustomer" is supposed to get the id of the customers from output of "createCustomer" method and use them as input, using ITestContext and ISuite.
#Test
public void testGetCustomer(ITestContext context) {
ISuite suite = context.getSuite();
//Rest-Assured code goes here
Assert.assertEquals(js.getString("customerID"), suite.getAttribute("customerID"));
}
When I run the test suite from the testng xml file, only the id of the third created customer will be passed to "getCustomer" method.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
<test verbose="2" preserve-order="true"
<classes>
<class name="addCustomer">
<methods>
<include name="testAddCustomer"/>
</methods>
</class>
</classes>
</test>
<test verbose="2" preserve-order="true"
<classes>
<class name="getCustomer">
<methods>
<include name="testGetCustomer"/>
</methods>
</class>
</classes>
</test>
</suite>
How can I change the settings or the code so that the "getCustomer" method gets called every time createCustomer is called and a customer created?
This would work for you.
//Create a temp list of String to save ID
static List<String> ids = new ArrayList<>();
#Test(dataProvider = "createCustomerTestData", dataProviderClass = createCustomerDataProvider.class)
public void addStockAccountWithAllInput(ITestContext context) throws JsonProcessingException {
//Rest-Assured code goes here
ISuite suite = context.getSuite();
String id = js.get("customerID");
ids.add(id);
suite.setAttribute("customerIDs", ids);
}
#Test
public void testGetCustomer(ITestContext context) {
ISuite suite = context.getSuite();
//Make api call based on the list IDs from above test
for (int i = 0; i < suite.getAttribute("customerIDs").size(); i++){
//Rest-Assured code goes here
Assert.assertEquals(js.getString("customerID"), suite.getAttribute("customerIDs").get(i));
}
}

TestNG Dataprovider closing driver after each iteration

I am trying to run a dataprovider based test using ANT. My main class points to testNG file
XmlSuite suite=new XmlSuite();
suite.setName("Test Results");
suite.setPreserveOrder(true);
List<XmlSuite> suits=new ArrayList<XmlSuite>();
suits.add(suite);
List<XmlPackage> xpackage=new ArrayList<XmlPackage>();
xpackage.add(new XmlPackage(TestProperties.TESTNG_PACKAGE.toString()));
XmlTest test=new XmlTest(suite);
test.setPackages(xpackage);
String groups=TestProperties.TESTNG_GROUP.toString();
System.out.println("groups are:"+groups);
String groupArray[]=groups.split(",");
List<String> includedGroups=new ArrayList<String>();
includedGroups.addAll(Arrays.asList(groupArray));
test.setIncludedGroups(includedGroups);
TestNG tng=new TestNG();
tng.setOutputDirectory("test-output");
tng.setXmlSuites(suits);
tng.run();
System.exit(0);
Now, in my Testcase file, I have
#BeforeClass(alwaysRun = true)
public void pretest() throws IOException, GeneralSecurityException {
Pretest
}
#Test(groups= {"indicatorGroup","",""},description = "Validate indicator uploaded", dataProvider = "getIndicatorData")
public void indicatorUpload(String txt){
test
}
#DataProvider
public Object[] getIndicatorData() throws IOException, GeneralSecurityException
{
bla bla
for(int i=0; i<contents.length; i++) {
System.out.println(contents[i]);
if(!contents[i].contains("README")) {
blah blah
System.out.println(path);
names.add(path);
}
}
String[] myArray = new String[names.size()];
names.toArray(myArray);
return myArray;
}
#AfterClass(alwaysRun = true)
public void afterMethod() throws IOException {
System.out.println("Deleting all files after operation.....");
}
The problem is, they run without any issues, if i run from Testng. ie if i right click on the file, click on run, click on Run as Testng Test.
But if I run from my build file, after the first iteration, the driver I bring up in before class, closes and the rest of the tests fail. This causes my tests to fail in jenkins.
Can someone please help me out?
After many trials, I found out that the testng xml created By my trigger file had
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="IndicatorSuite" data-provider-thread-count="1">
<test name="Test Basics 1">
<groups>
<run>
<include name="indicatorUpload" />
</run>
</groups>
<classes>
<class name="Uploads.IndicatorFileUpload">
<class name="Uploads.IndicatorFileUpload1">
<class name="Uploads.IndicatorFileUpload2">
</methods>
</class>
</classes>
</test>
</suite>
Even though my test group was correct, I had given test package, because of which all my testcase files had been added as classes. All of these had a listener which would close the driver after testrun. I dont know much about testng, but I think it mixed up the listeners. In my Trigger file, when I added just
TestNG tng=new TestNG();
tng.setOutputDirectory("test-output");
//tng.setXmlSuites(suits);
tng.setTestClasses(new Class[] { IndicatorFileUpload.class });
tng.run();
it worked!

TestNG does not continue execute tests after failure

I have test automation framework with a page object model.
All my test are located in separate classes in same package.
In testng.xml i have
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Smoke Test">
<test name="SmokeTest">
<classes>
<class name="name.test1"/>
<class name="name.test2"/>
<class name="name.test3"/>
</classes>
</test>
</suite>
Problem is that after running TestNG.xml if the 1st test will fail, it will stop test execution. But i want to continue executing of all test cases.
I use Jenkins on my project and if one of the tests are failed it stops execution immediately.
Example of test
public class LoginTestTest {
public AndroidDriver<AndroidElement> driver;
public AOWebClient aoWebClient;
AOWebClient aoWeb;
public LoginTestTest(AndroidDriver<AndroidElement> driver, AOWebClient aoWeb){
this.driver = driver;
this.aoWeb = aoWeb;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
public LoginTestTest() {
}
SoftAssert softAssert = new SoftAssert();
#BeforeClass
public void setUp() throws Exception {
driver = DesiredCapabilitiesSetup.startAppiumServer();
aoWebClient = DesiredCapabilitiesSetup.getAOWeb();
LogIn logIn = new LogIn(driver,aoWebClient);
logIn.logIn();
}
#org.testng.annotations.Test
public void goToSettings() throws InterruptedException {
HeaderMenu header = new HeaderMenu(driver,aoWeb);
HamburgerMenuList ham = new HamburgerMenuList(driver);
header.clickHamburgerButton();
header.clickHamburgerButton();
header.editButtonClick();
softAssert.assertAll();
}
#AfterClass
public void tearDown(ITestResult result) throws Exception {
if (result.getStatus() == ITestResult.FAILURE) {
TakeScreenshot screenshot = new TakeScreenshot();
screenshot.TakeScreenshot("screenshots/");
}
LogOut logOut = new LogOut(driver,aoWeb);
logOut.logOut();
}
}
If my test will fail in #Test it will never continue to #AfterClass method.
And I want that if #Test fail it will continue to #AfterClass method and After This Class continue executes test from other classes from testng.xml.
Your suite tag in your xml should include configfailurepolicy="continue". This tells testng that even though a config failed in one class, you still want to run other classes in that suite. See "configfailurepolicy" in the documentation.
So your xml would become:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Smoke Test" configfailurepolicy="continue">
<test name="SmokeTest">
<classes>
<class name="name.test1"/>
<class name="name.test2"/>
<class name="name.test3"/>
</classes>
</test>
</suite>
From the documentation:
alwaysRun: For after methods (afterSuite, afterClass, ...): If set to
true, this configuration method will be run even if one or more
methods invoked previously failed or was skipped.
Then, just replace your #AfterClass by #AfterClass(alwaysRun = true).
Add below attribute in testng.xml file under Suite syntax
<suite thread-count="25" name="Smoke" parallel="classes" skipfailedinvocationcounts="true">
Work for me, hope it will work for you as well :)

NullPointer exception in TestNG while run test using xml

Try to automate my test using TESTNG framework in eclipse.
In Project I use one packet iEDGE and write all test methods in single Class named eLogin.
But when I try to execute the code it shows nullPointer exceptions.
Following is my sample code and xml settings that I use to run my test case.
Can any one help me to resolve my problem.
Package com.iEDGE;
public class eLogIn {
private WebDriver driver;
private String baseUrl;
private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();
#Parameters ( { "platform", "browser", "ver" } )
#BeforeMethod (alwaysRun=true )
public void setUp(#Optional String platform , #Optional String browser , #Optional String version ) throws Exception {
baseUrl = "Gmail URL";
DesiredCapabilities mCapability = new DesiredCapabilities();
if (platform.equalsIgnoreCase("WINDOWS")){
mCapability.setPlatform(org.openqa.selenium.Platform.WINDOWS);
}
if (browser.equalsIgnoreCase("Firefox")) {
mCapability = DesiredCapabilities.firefox();
mCapability.setVersion("40");
}
driver = new RemoteWebDriver(new URL(baseUrl), mCapability);
driver.manage().timeouts().implicitlyWait(1000, TimeUnit.MILLISECONDS);
driver.get(baseUrl);
driver.findElement(By.cssSelector("input[name=username]")).clear();
driver.findElement(By.cssSelector("input[name=username]")).sendKeys("username");
driver.findElement(By.cssSelector("input[name=password]")).clear();
driver.findElement(By.cssSelector("input[name=password]")).sendKeys("password");
driver.findElement(By.id("button-1015-btnInnerEl")).click();
}
//OTEHR TEST METHODS ....
}
TESTSuite.xml Settings
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite guice-stage="DEVELOPMENT" name="Default suite">
<test verbose="2" name="Default test">
<parameter name="platform" value="Windows"/>
<parameter name="browser" value="Firefox"/>
<parameter name="ver" value="40.0.3"/>
<classes>
<class name="com.iEDGE.eLogIn"/>
</classes>
</test> <!-- Default test -->
</suite> <!-- Default suite -->
Since all your parameter are annotated with #Optional, you will have to check if they are null before calling their methods. So, for example, you will have to do something like this:
if(platform != null){
if (platform.equalsIgnoreCase("WINDOWS")){
mCapability.setPlatform(org.openqa.selenium.Platform.WINDOWS);
}
}
Do this for all the instructions that involves these optional parameters.
You are passing wrong URL into " RemoteWebDriver(new URL(baseUrl), mCapability); "
You should pass selenium server url like below:
new RemoteWebDriver( new URL("http://localhost:4444/wd/hub"),
mCapability);
For more details follow:
seleniumHq
Let me know if you have any concern
Thanks
Sadik
you are intializing wrong Base url.
is supposed to be
baseUrl = "http://127.0.0.1:4888/wd/hub";
you have to mention which transfer protocol is used in your local host.

TestNG, ITestContext - getIncludedGroups returns Null

There are several tests with different test groups. And I'm trying to run each of them with different set of data by using #DataProvider with ITestContext inside. I get NullPointerException. Here is my code:
String url = "http://google.com";
FirefoxDriver driver = new FirefoxDriver();
#BeforeTest(groups={"A","B"})
public void launchOfBrowser(){
driver.get(url);
}
#Test(dataProvider="Search", groups="A")
public void searchByUser(String author, String key) throws InterruptedException{
System.out.println("Welcome " + author + ", your search value is: " + key);
String enteredValue;
driver.findElement(By.name("q")).sendKeys(key);
Thread.sleep(3000);
enteredValue = driver.findElement(By.name("q")).getAttribute("value");
Assert.assertEquals(enteredValue, key);
driver.findElement(By.name("q")).clear();
}
#Test(dataProvider="Search", groups="B")
public void searchByIncognito(String key) throws InterruptedException{
System.out.println("Your search value is: " + key);
String enteredValue;
driver.findElement(By.name("q")).sendKeys(key);
Thread.sleep(3000);
enteredValue = driver.findElement(By.name("q")).getAttribute("value");
Assert.assertEquals(enteredValue, key);
driver.findElement(By.name("q")).clear();
}
#AfterTest(groups={"A","B"})
public void closeSessions(){
driver.quit();
}
#DataProvider(name="Search")
public static Object[][] getDataFromDataprovider(ITestContext c){
Object[][] groupArray = null;
for(String group : c.getIncludedGroups()){
if (group.equalsIgnoreCase("A")){
groupArray = new Object[][] {
{ "Guru99", "India" },
{ "Krishna", "UK" },
{ "Bhupesh", "USA" }
};
}
else{
groupArray = new Object[][] {
{ "India" },
{ "UK" },
{ "USA" }
};
}
}
return groupArray;
}
If you directly run your testng class, it will first call dataprovider which cant get groups information as groups are not available. But instead if you call this class via testng.xml, it will have groups info available with ITestContext.
You need to call this class(class name is say 'ParameterByITestContextInDataprovider') through TestNG xml.
Below is sample xml:-
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="test-parameter">
<test name="example1">
<groups>
<run>
<include name="A" />
</run>
</groups>
<classes>
<class
name="com.package123.ParameterByITestContextInDataprovider" />
</classes>
</test>
<test name="example2">
<groups>
<run>
<include name="B" />
</run>
</groups>
<classes>
<class
name="com.package123.ParameterByITestContextInDataprovider" />
</classes>
</test>
</suite>

Categories

Resources