TestNG Parallel execution with selenium driver factory - java

Trying to get a driver factory set up for a framework I am building as a learning tool. However I am struggling to get parallel execution of the test classes in testng.
I am using the surefire plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<properties>
<suiteXmlFiles>
<suiteXmlFile>src/main/resources/master.xml</suiteXmlFile>
</suiteXmlFiles>
</properties>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
The version of testng I am using is:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.10</version>
<scope>test</scope>
</dependency>
and the master.xml is as follows:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Parallel test suite" parallel="classes" thread-count="2">
<test name="Test 1">
<classes>
<class name="testsuite.TestCase1"/>
<class name="testsuite.TestCase2"/>
</classes>
</test>
</suite>
I have simplified the driver factory for the purposes of posting here:
public class DriverFactory
{
//protected WebDriver driver;
private DriverFactory()
{
//Do-nothing..Do not allow to initializethis class from outside
}
private static DriverFactory instance = new DriverFactory();
public static DriverFactory getInstance()
{
return instance;
}
ThreadLocal<WebDriver> driver = new ThreadLocal<WebDriver>() // thread local driver object for webdriver
{
#Override
protected WebDriver initialValue()
{
System.setProperty("webdriver.chrome.driver",
"src/main/resources/chromedriver.exe");
return new ChromeDriver(); // can be replaced with other browser drivers
}
};
public WebDriver getDriver() // call this method to get the driver object and launch the browser
{
return driver.get();
}
public void removeDriver() // Quits the driver and closes the browser
{
driver.get().quit();
driver.remove();
}
}
Using the following mvn command to run:
mvn clean test
I know this is going to be something stupid on my part having read almost every tutorial, blog post and document relating to this I cad find.
Any assistance even just pointing me off in the right direction is greatly appreciated.

TestNG allows you to run your tests in parallel, including JUnit tests. To do this, you must set the parallel parameter, and may change the threadCount parameter if the default of 5 is not sufficient. You have to set configuration parameters:
<configuration>
<parallel>methods</parallel>
<threadCount>10</threadCount>
</configuration>
For you:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<parallel>methods</parallel>
<threadCount>10</threadCount>
<properties>
<suiteXmlFiles>
<suiteXmlFile>src/main/resources/master.xml</suiteXmlFile>
</suiteXmlFiles>
</properties>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
UPDATE
try the following
<suite name="Parallel test suite" parallel="classes" thread-count="2">
<test name="Test 1">
<classes>
<class name="testsuite.TestCase1"/>
</classes>
</test>
<test name="Test 2">
<classes>
<class name="testsuite.TestCase2"/>
</classes>
</test>

I resolved it myself all the suggestions made were correct and the logic I posted was originally correct as well.
However, the test cases themselves were not.
public class TestCase1 {
LandingPage page = new LandingPage();
#BeforeMethod
public void beforeMethod() throws Exception {
page.navigate();
}
#Test (priority = 1, description="SS1 Verify the login section")
#Description ("Verify that user mngr116116 can logon to the system")
public void login()
{
System.out.println("Test Case One in " + getClass().getSimpleName()
+ " with Thread Id:- " + Thread.currentThread().getId());
page.enterUser("mngr116116");
page.enterPass("ytUhUdA");
page.submitBtn();
}
#AfterMethod
public void validate(){
Assert.assertEquals(LandingPage.getExpectedPageTitle(),
page.getObservedPageTitle());
}
}
This was causing the issue replace it with:
public class TestCase1 {
LandingPage page;
#BeforeMethod
public void beforeMethod() throws Exception {
page = new LandingPage();
page.navigate();
}
#Test (priority = 1, description="SS1 Verify the login section")
#Description ("Verify that user mngr116116 can logon to the system")
public void login()
{
page = new LandingPage();
System.out.println("Test Case One in " + getClass().getSimpleName()
+ " with Thread Id:- " + Thread.currentThread().getId());
page.enterUser("mngr116116");
page.enterPass("ytUhUdA");
page.submitBtn();
}
#AfterMethod
public void validate(){
page = new LandingPage();
Assert.assertEquals(LandingPage.getExpectedPageTitle(),
page.getObservedPageTitle());
}
}
And I am in business.
Thanks for the help

Related

How to run #BeforeSuite and #AfterSuite methods defined in another class before the execution of the step def class starts?

Can someone explain why I am not able to run this cucumber, testng project? Below is the code:
TestRunner.java:
package runner;
import org.testng.annotations.Test;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
#CucumberOptions(
features = {"src/test/resources/features"},
glue = "steps",
plugin = {"pretty", "json:target/json-report/cucumber.json"},
dryRun = false,
monochrome = true
)
#Test
public class TestRunner extends AbstractTestNGCucumberTests {
}
GithubLoginPageSteps.java:
package steps;
import static org.testng.Assert.fail;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class GithubLoginPageSteps extends CommonSteps {
private WebDriver driver;
public GithubLoginPageSteps(CommonSteps commonSteps) {
System.out.println("Inside CitiHomePageSteps() ");
this.driver = commonSteps.getDriver();
}
#Given("I am on the {string}")
public void i_am_on_the(String githubHomePageUrl) throws InterruptedException {
System.out.println(githubHomePageUrl);
driver.get(githubHomePageUrl);
Thread.sleep(2000);
}
#When("the user enters the right {string} and {string}")
public void the_user_enters_the_right_and(String username, String pwd) {
driver.findElement(By.xpath("//*[#id=\"login_field\"]")).click();
driver.findElement(By.xpath("//*[#id=\"login_field\"]")).sendKeys(username);
driver.findElement(By.xpath("//*[#id=\"password\"]")).click();
driver.findElement(By.xpath("//*[#id=\"password\"]")).sendKeys(pwd);
}
#When("the user clicks on the sign on button")
public void the_user_clicks_on_the_sign_on_button() throws InterruptedException {
driver.findElement(By.xpath("//*[#id=\"login\"]/div[4]/form/div/input[12]")).click();
Thread.sleep(000);
}
#Then("the user is navigated to the {string}")
public void the_user_is_navigated_to_the(String githubDashboardUrl) {
String actualUrl = driver.getCurrentUrl();
String expectedUrl = githubDashboardUrl;
System.out.println("Actual url is:"+ actualUrl);
System.out.println("Expected url is:"+ expectedUrl);
driver.quit();
if(!actualUrl.equals(expectedUrl)) {
fail("Dashboard url didn't match the expected url:"+ expectedUrl);
}
}
}
CommonSteps.java:
package steps;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import io.cucumber.java.Scenario;
public class CommonSteps {
private WebDriver driver;
#BeforeSuite
public void setUp() {
System.setProperty("webdriver.chrome.driver", "src/test/resources/webdriver/chromedriver.exe");
driver = new ChromeDriver();
System.out.println("Inside #BeforeSuite hook");
}
#AfterSuite
public void tearDown(Scenario scenario) {
System.out.println("Inside #AfterSuite hook");
driver.quit();
}
public WebDriver getDriver() {
System.out.println("Inside getDriver()");
return this.driver;
}
}
testng.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
<test thread-count="5" name="Test">
<classes>
<class name="runner.TestRunner"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shri.automation</groupId>
<artifactId>Cucumber-TestNg2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Cucumber-TestNg2</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.4.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>6.10.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>6.10.4</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0-beta-4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>6.10.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>2.8.0</version>
<executions>
<execution>
<id>execution</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<skip>false</skip>
<outputDirectory>${project.build.directory}/masterthought-report</outputDirectory>
<cucumberOutput>${project.build.directory}/json-report/cucumber.json</cucumberOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
GithubLoginFeaturePage.feature:
Feature: Github Login Page
Scenario Outline: Github Login
Given I am on the '<GithubLoginPage_url>'
When the user enters the right '<username>' and '<password>'
And the user clicks on the sign on button
Then the user is navigated to the '<Github_dashboard_url>'
Examples:
|GithubLoginPage_url|username|password|Github_dashboard_url|
|https://github.com/login|abc#gmail.com|1234|https://github.com/|
[Project structure link][1]
[1]: https://i.stack.imgur.com/qAFom.png
The error I get is:
java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.WebDriver.get(String)" because "this.driver" is null
at steps.GithubLoginPageSteps.i_am_on_the(GithubLoginPageSteps.java:27)
I think I found the reason why that 'driver is null error' was coming in the GithubLoginPageSteps. Because in the testng.xml file I forgot to add the inside the of the named 'Test'. And then I need to make the 'driver' variable in CommonSteps as static so that the same copy is used across all instances of the CommonSteps class.
This is necessary because two instances of the CommonSteps would be created when I now run the testng.xml file, one to run the CommonSteps.java class defined in the testng.xml where the 'driver' would be initialized and then in the GithubLoginSteps.java I am also injecting the CommonSteps class instance using the cucumber picocontainer and then use this to get the 'driver'. So you see if I don't declare the driver as static then there is no way 'driver' would be initialized in the CommonSteps.java and it would remain as null.
Also I found that I don't even need to extend the CommonSteps class inside the GithubLoginPageSteps class and the thread-count attribute in the testng.xml is also redundant.
With these changes I tried to run the code and it worked!

TestNG : Test case is ignored

I am using TestNG framework for writing test cases for my Android application. For which I am using Appium testing tool.
For this I have defined following files :
pom.xml file - required for dependencies
One BaseTest.java class
Two child classes which is extended from BaseTest.java
testng.xml file - defines running test classes in it.
For better understanding of my question posting classes & xml files.
This is pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.testing</groupId>
<artifactId>android-appium</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
This is BaseTest.java class
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
public class BaseTest {
#BeforeSuite
public void setUp()
{
}
#AfterSuite
public void tearDown()
{
}
}
This is FirstTest.java class
import io.appium.java_client.MobileBy;
import io.appium.java_client.MobileElement;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.PointOption;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import scenarios.BaseTest;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class FirstTest extends BaseTest {
private AndroidDriver<MobileElement> mAndroidDriver;
#BeforeTest
protected void setUpDriver() throws MalformedURLException {
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability("device", "Android");
desiredCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "abfg34e");
desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.0");
desiredCapabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "UiAutomator1");
desiredCapabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.example.test");
desiredCapabilities.setCapability(MobileCapabilityType.APP,"/home/desktop/app-developer-debug.apk");
desiredCapabilities.setCapability(MobileCapabilityType.NO_RESET, "true");
mAndroidDriver = new AndroidDriver(new URL(Constants.BASE_URL), desiredCapabilities);
System.out.println("setUpDriver() :: time : "+ DateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
}
#Test(groups = "app_screen_group_1", priority = 1)
public void splashScreen_1() throws InterruptedException {
System.out.println("splashScreen_1() :: startTime : "+ DateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
Thread.sleep(7000);
}
#Test(groups = "app_screen_group_1", priority = 2)
public void splashScreen_2() throws InterruptedException {
System.out.println("splashScreen_2() :: startTime : "+ DateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
MobileElement menuElement = mAndroidDriver.findElementByAccessibilityId("More options");
menuElement.click();
Thread.sleep(10);
MobileElement splashElement = mAndroidDriver.findElementByAndroidUIAutomator("new UiSelector().text(\"Splash\")");
splashElement.click();
}
}
This is SecondTest.java class
import io.appium.java_client.MobileBy;
import io.appium.java_client.MobileElement;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.PointOption;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import scenarios.BaseTest;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class SecondTest extends BaseTest {
private AndroidDriver<MobileElement> mAndroidDriver;
#Test(groups = "app_screen_group_2", priority = 1)
public void logInScreen_1() throws InterruptedException {
System.out.println("logInScreen_1() :: startTime : "+ DateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
Thread.sleep(7000);
}
#Test(groups = "app_screen_group_2", priority = 2)
public void logInScreen_2() throws InterruptedException {
System.out.println("logInScreen_2() :: startTime : "+ DateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
MobileElement menuElement = mAndroidDriver.findElementByAccessibilityId("More options");
menuElement.click();
Thread.sleep(10);
MobileElement logInElement = mAndroidDriver.findElementByAndroidUIAutomator("new UiSelector().text(\"Log in\")");
logInElement.click();
}
}
This is testng.xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="androidapp" group-by-instances="true">
<test name="FirstScenario_1" >
<classes>
<class name="scenarios.FirstTest" ></class>
<class name="scenarios.SecondTest"></class>
</classes>
</test>
<!-- Following scenario runs perfectly if I have each separate class in separate test name. But in above case scenario it is not working properly, it gives Test ignored error for second method of FirstTest.java
<test name="secondScenario_1" >
<classes>
<class name="scenarios.FirstTest" ></class>
</classes>
</test>
<test name="secondScenario_2" >
<classes>
<class name="scenarios.SecondTest" ></class>
</classes>
</test>-->
</suite>
When I run this code using appium tool then on second function splashScreen_2() of FirstTest.java class got error Test ignored & it is not running properly. But when I do uncomment secondScnario_2 in testng.xml file & comment FirstScenario_1 then my test cases run properly (as I mention in comment also) & android app executes each function properly one by one.
But I want to do execute all classes in <test> </test> functions in testng.xml.
If I use secondScnario_2 in testng.xml file then I need to give separate test name for each scenario. And I want to use only one test name. So here when I use FirstScenario_1 in testng.xml file, Why is their an error of test ignored ocurring here?
Based on what you have described in comments , I think you want to run everything in order by defining all classes in one test. Then you should remove priorities and groups and run it with this xml with preserve-order="true" . This should run test in the order they are defined in xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="androidapp" >
<test name="FirstScenario_1" preserve-order="true">
<classes>
<class name="scenarios.FirstTest" >
<methods>
<include name="setUpDriver" />
<include name="splashScreen_1" />
<include name="splashScreen_2" />
</methods>
</class>
<class name="scenarios.SecondTest">
<methods>
<include name="logInScreen_1" />
<include name="logInScreen_2" />
</methods>
</class>
</classes>
</test>
</suite>
You can also use #dependsOnMethods to run methods in the order you want . Have a look at this . The ordering described there should also help you to resolve this

Error org.testng.TestNGException: Cannot inject #Test annotated Method main with class Ljava.lang.String;

I have created a testng.xml file to run a suite of my selenium webdriver test. From eclipse I can run this just fine as a testNG Suite, but from the command like I get the following error.
testng.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "testng.org/testng-1.0.dtd">;
<suite name="CATS Regression Suite">
<test name="WEB UI">
<parameter name="uid" value="TestAccount"/>
<parameter name="pid" value="Test123"/>
<classes>
<class name="VerifyLogin"/>
</classes>
</test>
<!-- Test -->
</suite>
<!-- Suite -->
command ran:
java org.testng.TestNG testng.xml
Exception trace:
[Error] org.testng.TestNGException:
Cannot inject #Test annotated Method [main] with [class [Ljava.lang.String;].
For more information on native dependency injection please refer to http://testng.org/doc/documentation-main.html#native-dependency-injection
at org.testng.internal.Parameters.checkParameterTypes(Parameters.java:244)
at org.testng.internal.Parameters.createParameters(Parameters.java:172)
at org.testng.internal.Parameters.createParameters(Parameters.java:458)
at org.testng.internal.Parameters.handleParameters(Parameters.java:568)
at org.testng.internal.Invoker.handleParameters(Invoker.java:1293)
at org.testng.internal.Invoker.createParameters(Invoker.java:1020)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1110)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:756)
at org.testng.TestRunner.run(TestRunner.java:610)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:387)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:382)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
at org.testng.SuiteRunner.run(SuiteRunner.java:289)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1293)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1218)
at org.testng.TestNG.runSuites(TestNG.java:1133)
at org.testng.TestNG.run(TestNG.java:1104)
at org.testng.TestNG.privateMain(TestNG.java:1434)
at org.testng.TestNG.main(TestNG.java:1403)
Code (As shared in the comments)
public class VerifyLogin extends TestBase {
#Parameters({"uid","pid"})
#Test
public void verifyLogin(String uid, String pid) throws IOException, Exception {
String userName = uid;
String passWord = pid;
// new instance
ExtentReports extent = new ExtentReports("C:\\Users\\AdvancedReport.html", true);
//starting test
ExtentTest test = extent.startTest("Login Test", "Regression");
// log step
test.log(LogStatus.PASS, "Browser Running");
TestBase login=new TestBase();
login.testLogin(userName, passWord);
}
}
Just remove String uid, String pid in main method and run once again as
public void verifyLogin(String uid, String pid)
to
public void verifyLogin()
If you want to give parameters in #Test method, then you need to provide valid data provider.

Second class of testing.xml doesn't execute

I have created 2 separate classes to test a webpage. But, unfortunately when I add them both to the testing.xml, only one of them execute and the other doesn't. The browsers open in parallel even after setting them to preserve-order="true" parallel="false" in the XML. I'm confused as to where I'm doing it wrong.
This is my XML file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" preserve-order="true" parallel="false">
<test name="Test">
<classes>
<class name="TestServiceNow.loginOne"/>
<class name="TestServiceNow.loginTwo"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
loginOne is as follows:
package TestServiceNow;
import org.testng.annotations.Test;
import ServiceNow.login;
public class loginOne extends loginTest{
#Test
public void test_Login(){
//Create Login Page object
objLogin = new login(driver);
//login to application
objLogin.loginGurukula("admin", "admin");
}
}
loginTwo is as follows:
import org.testng.annotations.Test;
import ServiceNow.login;
public class loginTwo extends loginTest{
#Test
public void test_Login_Fail(){
//Create Login Page object
objLogin = new login(driver);
//login to application
objLogin.loginGurukula("admin", "admin1");
}
}
The base class is as follows:
public class loginTest {
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
File file = new File("C:/Users/gattu_000/Documents/selenium-java-3.0.0-beta2/chromedriver_win32/chromedriver.exe");
WebDriver driver;
login objLogin;
#BeforeClass
public void a() {
driver = new ChromeDriver(capabilities);
capabilities.setCapability("marionette", true);
System.setProperty("webdriver.chrome.driver", file.getAbsolutePath());
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
System.out.println("Before class called");
}
#BeforeTest
public void setup(){
System.out.println("Before test called");
driver.get("http://localhost:8080/#/login");
}
#AfterTest
public void close() {
System.out.println("After test called");
}
#AfterClass
public void b() {
System.out.println("After class called");
driver.close();
}
}
The results look like
After the Edit
You are extending loginTest by both loginOne and loginTwo. But in loginTest you initialized your driver. That's why two browser are opening. To get around this issue, you can initialize your driver inside a setup method like #BeforeTest or #BeforeSuite. As an example here's a code snippet -
#BeforeSuite
public void a() {
driver = new ChromeDriver(capabilities);
System.out.println("Before suite called");
}
Do other things as usual like before except the initialization part.
Edit
I missed something. You are closing your driver at the after test method. To run your tests properly remove the driver.close() from your after test method and place it to aftereSuite section.
The XML is supposed to be like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" preserve-order="true">
<test name="Test">
<classes>
<class name="TestServiceNow.loginOne"/>
</classes>
</test> <!-- Test -->
<test name="Test1">
<classes>
<class name="TestServiceNow.loginTwo"/>
</classes>
</test>
</suite> <!-- Suite -->
To launch the browser twice, we need to have 2 separate tests. (Possibly, this may be one of the solutions out of many)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Selenium Test Suite">
<test name="Selenium Test Suite">
<classes>
<class name="packagename.classname1"/>
<class name="packagename.classname1"/>
</classes>
</test>
</suite>
Which is proper. If you are getting null point don't use driver in all the class. because of that only you are getting null pointer i guess.

How to write multiple Selenium WebDriver session logs into different files when they run parallel using java

Looking for a solution to write step by step execution details of Selenium webDriver scripts into a file. Logs need to be added to files which are created for each 'Tests' in testng.xml and are running on the different browser.
That has been achieved for 'one session' by implementing WebDriverEventListener.(But I don't have an idea of writing each driver instance custom logs into different files within a single method)
But looking for a solution to bind each 'log files' with 'Webdriver instances' and write respective browser actions into it.
#Parameters({"BrowserName"})
#BeforeTest
public void createDriver(String BrowserName) {
switch (BrowserName) {
case "Chrome":
System.setProperty("webdriver.chrome.driver",
System.getProperty("user.dir") + "//BrowserExes//chromedriver.exe");
Driver = new ChromeDriver();
eventFiringDriver = new EventFiringWebDriver(Driver);
eventListener = new CustomWebDriverListener(Driver);
eventFiringDriver.register(eventListener);
break;
case "IE":
System.setProperty("webdriver.ie.driver",
System.getProperty("user.dir") + "//BrowserExes//IEDriverServer.exe");
Driver = new InternetExplorerDriver();
eventFiringDriver = new EventFiringWebDriver(Driver);
eventListener = new CustomWebDriverListener(Driver);
eventFiringDriver.register(eventListener);
default:
break;
}
}
#Test
public void loadURL(){
eventFiringDriver.get("https://www.google.com");
}
I have created report files by implementing ISuiteListener based on the number of TestNG tests.
<suite name="Suite" parallel="tests">
<test name="Test">
<parameter name="BrowserName" value="Chrome"></parameter>
<classes>
<class name="eventFiringWebDriver.EventDriver"></class>
</classes>
</test>
<test name="Test_2">
<parameter name="BrowserName" value="IE"></parameter>
<classes>
<class name="eventFiringWebDriver.EventDriver"></class>
</classes>
</test>
You should be able to do this very easily if you rely on a logging framework such as SLF4j.
On a highlevel you need to leverage a SiftingAppender that SLF4j provides you and inject values to the variables that you refer to in your logback.xml from your code.
I have captured all of this information in this blog post of mine with a sample as well.
But for the sake of reference I am including the bare essentials here in this post as well.
Here's how my logback.xml looks like
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator>
<key>fileName</key>
<defaultValue>defaultTest</defaultValue>
</discriminator>
<sift>
<appender name="FILE-${fileName}" class="ch.qos.logback.core.FileAppender">
<file>${fileName}.log</file>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm:ss:SSS} | %-5level | %thread | %logger{20} | %msg%n%rEx</pattern>
</layout>
</appender>
</sift>
</appender>
<root level="ALL">
<appender-ref ref="SIFT"/>
</root>
</configuration>
Here's a modified listener for injecting into EventFiringWebDriver
public class LogAwareWebDriverEventListener extends AbstractWebDriverEventListener{
#Override
public void beforeNavigateTo(String url, WebDriver driver) {
LoggerFactory.getLogger(getClass()).info("Loading url " + url);
}
public void bindLogName(String log, String folderName) {
String path = new File(folderName).getAbsolutePath() + File.separator;
MDC.put("fileName", path + log);
}
public void unbind() {
MDC.remove("fileName");
}
}
Here's how a test case looks like which uses all of this.
public class ManyTestCases {
#Test
public void testMethod1() {
runTest("http://www.google.com");
}
#Test
public void testMethod2() {
runTest("http://www.yahoo.com");
}
private void runTest(String url) {
ChromeDriver cd = new ChromeDriver();
EventFiringWebDriver driver = new EventFiringWebDriver(cd);
LogAwareWebDriverEventListener listener = new LogAwareWebDriverEventListener();
String outputFolder = Reporter.getCurrentTestResult().getTestContext().getSuite().getOutputDirectory();
listener.bindLogName(Reporter.getCurrentTestResult().getName(), outputFolder);
driver.register(listener);
driver.get(url);
driver.quit();
listener.unbind();
}
}
Maven dependencies :
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
References :
https://dzone.com/articles/adding-slf4j-your-maven
https://dzone.com/articles/siftingappender-logging
https://stackoverflow.com/a/6545048/679824 (Referred this to figure out how to work with multiple discriminators in SLF4j )

Categories