I have a script setup developed using Appium and TestNG. The TestNG xml contains execution of multiple classes and each class has multiple test cases.
Example:
Class1:
-Class1_Test1
-Class1_Test2
-Class1_Test3
Class2:
-Class2_Test1
-Class2_Test2
-Class2_Test3
I tried integrating IRetryAnalyzer but that just calls the failed test case. The requirement is to execute the complete Class1 in case Class1_Test2 fails as soon as Class1 fails before it proceeds to Class2?
The reason for the ask is the app is a media player and if in case media playback fails due to network/server issues, next test cases of forward and rewind will not be required to be executed and it will need to relaunch the app and retry all steps before performing further tests.
There is no way to achieve this as per TestNg documentation, might be below answer can help you
Retry Logic - retry whole class if one tests fails - selenium
I am using the group test. It will continue the test even if some test fail in the class.
In your class file you can define group like following.
public class myClass(){
#Test(groups = {"abc"}, priority = 1)
public void test1(){
}
#Test(groups = {"abc"}, priority = 2)
public void test2(){
}
#Test(groups = {"abc"}, priority = 3)
public void test3(){
}
}
similarly you can define second class with same group name or different group name. Priority determines the order in which test case runs.
Your Testng.xml file will be look like following:
<test name="any name">
<groups>
<run>
<include name="abc" />
<include name="any other group name" />
</run>
</groups>
<classes>
<class name="packageName.myClass"/>
<class name="your_packageName.class2"/>
</classes>
</test>
packageName is the path where your Test class is located. If your test class and testng.xml files are in same package, packageName is not required.
For more information about test method in Testng refer this link.
Finally found a workaround to rerun the whole class. I would call it a workaround since technically TestNG does not provide a way to re-execute #BeforeTest in case a failure occurs at any point of time.
The best possible method I found was to have no #BeforeTest section and have just one #Test section and have all Test cases as functions which would be called within the single #Test defined. So in case a failure occured at any point of time, the #Test would be recalled which contains all the functions in the order required including setting up the capabilities. The retry logic reruns the entire #Test section as soon as a failure is observed.
Example:
Before the changes:
package <yourpackagename>;
<import required packages>
public class Home {
private AppiumDriver<?> driver;
private static final String url = "http://0.0.0.0:4723/wd/hub";
<define your variables>
#Parameters({"deviceOS", "DSN"})
#BeforeTest
public void setUp(String deviceOS, String DSN) throws InterruptedException, MalformedURLException, ParseException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
capabilities.setCapability("deviceName", "FireTVStick");
capabilities.setCapability("platformVersion", deviceOS);
capabilities.setCapability("udid", DSN);
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("noReset", true);
capabilities.setCapability("fullReset", false);
capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1200);
capabilities.setCapability("appPackage", "<your app package>");
capabilities.setCapability("appActivity", "<your launcher activity>");
driver = new AndroidDriver<>(new URL(url), capabilities);
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//End of Launch Code
System.out.println("-Testing Home Section-");
}
#Parameters({"DSN"})
#Test
public void Test1_VideoPlaybackVerification(String DSN) throws InterruptedException, ParseException{
//Video playback verification code starts
.
.
//End of code for Video playback verification
}
#Test //Test Case for Pause verification
public void Test2_PauseVerification() throws InterruptedException, ParseException{
//Video pause verification code starts
.
.
//End of code for Video pause verification
}
#AfterTest
public void End() {
driver.quit();
}
}
After the changes:
package <yourpackagename>;
<import required packages>
#Listeners(MyTestListenerAdapter.class)
public class Home {
private AppiumDriver<?> driver;
<define your variables>
public void setUp(String port, String deviceOS, String DSN, String deviceName) throws InterruptedException, MalformedURLException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
capabilities.setCapability("platformVersion", deviceOS);
capabilities.setCapability("deviceName", deviceName);
capabilities.setCapability("udid", DSN);
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("noReset", true);
capabilities.setCapability("fullReset", false);
capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1200);
capabilities.setCapability("appPackage", "<your app package>");
capabilities.setCapability("appActivity", "<your launcher activity>");
final String url = "http://127.0.0.1:"+port+"/wd/hub";
driver = new AndroidDriver<>(new URL(url), capabilities);
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
}
public void HomeVerification(String DSN, String deviceName) throws InterruptedException, ParseException
{
System.out.println(deviceName+": Testing Home Section-");
<--Your code to perform any additional task before execution-->
}
public void Test1_VideoPlaybackVerification(String DSN, String deviceName) throws InterruptedException, ParseException
{
//Video playback verification code starts
.
.
//End of code for Video playback verification
}
public void Test2_PauseVerification(String deviceName) throws InterruptedException, ParseException
{
//Video pause verification code starts
.
.
//End of code for Video pause verification
}
#Parameters({"port", "deviceOS", "DSN", "deviceName"})
#Test (retryAnalyzer = Retry.class)
public void TestRun(String port, String deviceOS, String DSN, String deviceName) throws InterruptedException, ParseException, MalformedURLException {
try {
setUp(port, deviceOS, DSN, deviceName);
HomeVerification(DSN, deviceName);
Test1_VideoPlaybackVerification(DSN, deviceName);
Test2_PauseVerification(deviceName);
} catch (WebDriverException e) {
// TODO Auto-generated catch block
Reporter.log(deviceName+": Error observed while executing script!", true);
Assert.assertTrue(false); //Fails the test case
}
}
#AfterTest
public void End() {
driver.quit();
}
}
Related
I am trying to add ExtentReport in my test automation project, but IntelliJ is throwing this error at line "report = ..." inside "BeforeMethod"
Expected 0 arguments but found 1
I am trying to insert the location of the report file. Help much appreciated. Thanks.
public class Methods {
public static WebDriver driver;
public static ExtentReports report;
public static ExtentTest test;
#BeforeTest
public void startReport(){
report = new ExtentReports(System.getProperty("C:\\Program Files (J)\\VCWebMaine\\Report.html"));
}
#BeforeMethod
public void setDriver() throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "C:\\Program Files (J)\\VCWebMaine\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://xxxxxxxxxxxxxxxx");
Thread.sleep(2000);
}
I tried looking for answers in Google. It looks like the same lines work in Eclipse. Is it a problem in the IDE?
Other part of the script as below:
public class TestCases extends Methods {
ExtentTest test = Methods.test;
#Test
public void scenario01() throws InterruptedException, IOException {
I have 3 test methods using driver from Base class. I tired to run these methods in parallel but getting failures. Reponse to my problem is appreciated. Thanks
Class having 3 test methods
public class TestCases extends BaseClass {
#Test
public void Test1() {
homePage.checkIfElementIsDisplayed(homePage.emailElement);
homePage.checkIfElementIsDisplayed(homePage.passwordElement);
homePage.checkIfElementIsDisplayed(homePage.signInElement);
homePage.emailElement.sendKeys("karteek#gmail.com");
homePage.passwordElement.sendKeys("******");
}
#Test
public void Test2() {
homePage.checkValuesInListGroup();
homePage.checkSecondListItem();
homePage.checkSecondListItemBadgeValue();
}
#Test
public void Test3() throws InterruptedException {
homePage.ScrolltotheElement(homePage.dropDownOption);
homePage.checkDefaultSelectedValue();
homePage.selectOption3();
}
}
Base Class
public class BaseClass {
public WebDriver driver;
public HomePage homePage;
public WebDriver setup() throws IOException {
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(
System.getProperty("user.dir") + "\\src\\main\\resource\\GlobalData.Properties");
prop.load(fis);
String browserName = System.getProperty("browser") != null ? System.getProperty("browser")
: prop.getProperty("browser");
if (browserName.contains("chrome")) {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
}
else if (browserName.contains("edge")) {
WebDriverManager.edgedriver().setup();
driver = new EdgeDriver();
} else if (browserName.contains("firefox")) {
WebDriverManager.firefoxdriver().setup();
driver = new FirefoxDriver();
}
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
driver.manage().window().maximize();
return driver;
}
#BeforeMethod
public HomePage LaunchApplication() throws IOException {
driver = setup();
homePage = new HomePage(driver);
homePage.goTo();
return homePage;
}
#AfterMethod
public void tearDown() throws IOException {
driver.close();
}
I tried creating ThreadLocal Class for WebDriver as
ThreadLocal<WebDriver> threadSafeDriver=new ThreadLocal<WebDriver>();
and use this in setup() method of BaseClass by writing
threadSafeDriver.set(driver);
but this didnot really help
Most likely you are using the TestNG framework. One of the differences between JUnit and TestNG is that JUnit creates a new class instance for each test method by default but TestNG creates a single instance for all test methods in the class.
You can see the parallel option in TestNG suite (see docs) but there is no way to force TestNG to create a new instance for each test.
The simplest solution is to switch to JUnit framework. Then the code from the example should work.
I am new to TestNG. I am able to do parallel testing with BeforeMethod and AfterMethod class where I am opening new driver and closing the same respectively.
Below is my code:
#BeforeMethod
public void run() {
driver.get().get(url);
driver.get().manage().window().maximize();
driver.get().manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
Demo_Page objDemoPage = new Demo_Page(driver.get(), prop, date);
objDemoPage.admin_demo("local");
Home_page objHomePage = new Home_page(driver.get(), prop, date);
objHomePage.pwd_change_later();
}
public WebDriver getDriver() {
return driver.get();
}
#AfterMethod
public void tearDown() {
getDriver().quit();
}
#Test(priority = 1)
public void Testcase1(String switch_browser, String domain_drop, String mode, String
domain, String first_name,
String last_name, String login_name, String emp_id, String pwd, String
conf_pwd, String simp_name,
String case_type, String manage_tab, String create_user, String account_tab,
String OU, String button_id,
String protect) {
WebDriver driver = getDriver();
XXX
XXX
XXX
}
Similarly, I have N number of #Test methods.
And my testNG will look like
<suite name="Suite" parallel="tests" thread-count="2">
<listeners>
<listener class-name="listeners3.Proj_Listener" />
</listeners>
followed by Test tags.
Here, each time, the driver is launched and corresponding tests are run and then the driver is closed. But, I want the thread-count times of browser to be launched for the very first time, and remaining test cases to be run on the same browsers(same thread whichever is available) instead of closing and launching again.
Could anyone please help?
Add this below method with the annotation to the test class.
#BeforeClass
public void before_class()
{
System.out.println("This method is executed before Class1 and class1 has your above test methods");
//Declare the driver at the class level : public WebDriver driver;
driver = new XXXDriver();
//now this object will be available to you across all the tests in the class
}
I have a Base class with a method to open my URL that is called as #BeforeMethod in my test cases. The method takes a string argument for browser type which determines which browser is called. I am attempting to set a parameter in my xml launch file that can be inputted in my #BeforeMethod as argument for the openURL method.
Here is my XML file:
<?xml version="1.0" encoding="UTF-8"?>
<suite name="FullRegressionSuite" parallel="false">
<listeners>
<listener class-name="reporting.CustomReporter"></listener>
</listeners>
<test name="Test">
<parameter name ="browserType" value="Chrome"/>
<classes>
<class name="reporting.reporterTest"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
Here are my tests:
#Listeners(CustomListener.class)
public class reporterTest extends Base {
#Test
public void testOne() {
Assert.assertTrue(true);
}
#Test
public void testTwo() {
Assert.assertTrue(false);
}
#Parameters({ "browserType" })
#BeforeMethod
public void setUp(String browserType) throws InterruptedException {
System.out.println(browserType);
openURL(browserType);
}
#AfterMethod
public void tearDown() {
driver.quit();
}
}
Here is my base class:
public class Base {
public static WebDriver driver = null;
//CALL WEB BROWSER AND OPEN WEBSITE
public static void openURL(String browser) throws InterruptedException {
//launches browser based on argument given
try{
if (browser == "Chrome") {
System.setProperty("webdriver.chrome.driver", "/Users/rossdonohoe/Desktop/SeleniumJava/Drivers/chromedriver");
driver = new ChromeDriver();
}
else if (browser == "Firefox") {
System.setProperty("webdriver.gecko.driver", "/Users/rossdonohoe/Desktop/SeleniumJava/Drivers/geckodriver");
driver = new FirefoxDriver();
}
else {
System.out.println("Error: browser request not recognized");
}
driver.manage().deleteAllCookies();
driver.manage().window().maximize();
driver.get("https://www.google.com");
}
catch(Exception E) {
E.printStackTrace();
}
}
}
My #BeforeMethod is definitely receiving the parameter, as I'm printing its value to check and I'm getting "Chrome" in the console. However, openURL is failing at the 'delete all cookies' line with a null pointer exception (and my line "Error: browser request not recognized' is being printed in console), indicating that the string is not reaching openURL as an argument. Can anyone see what I'm doing wrong?
As the browser is a String variable , you need to use equals or contains or equalsIgnoreCase to check if the browser that you are fetching is "Chrome" or "Firefox".
So you need to use: if(browser.equals("Chrome")) and if(browser.equals("Firefox")) as the conditions instead of the conditions that you have used.
I am new to Appium, In my code I have given required desired capabilities and wrote one test case that is working fine. Now I want to launch another App for second test in same code , how can I do that ?
I heard about startActivity(app-package,app Activity) but its not working, it says startActivity() not defined for Web Driver .
public class Calculator {
WebDriver driver;
#BeforeClass
public void setUp() throws MalformedURLException{
//Set up desired capabilities and pass the Android app-activity and app-package to Appium
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, "Android");
capabilities.setCapability(CapabilityType.VERSION, "4.4");
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("deviceName", "14085521650378");
capabilities.setCapability("appPackage", "com.android.calculator2"); // This is package name of your app (you can get it from apk info app)
capabilities.setCapability("appActivity","com.android.calculator2.Calculator");
configurations specified in Desired Capabilities
driver = new RemoteWebDriver(new URL("http://127.0.0.1:9515/wd/hub"), capabilities);
}
#Test
public void testCal(){
driver.findElement(By.name("2")).click();
driver.findElement(By.name("+")).click();
driver.findElement(By.name("4")).click();
driver.findElement(By.name("=")).click();
}
#Test
public void Test2() { driver.startActivity("appPackage", "com.tttk.apc","appActivity","com.tttk.apc.DWDemoActivity");
for(int i=0; i<20;i++)
driver.findElement(By.className("android.widget.ImageButton")).click();
}
#AfterClass
public void teardown(){
//close the app
driver.quit();
}}
Seems like you are trying to use the method with a WebDriver instance.
The startActivity method is provided by an interface StartsActivity implemented by AndroidDriver only. So ideally this shall work :
((AndroidDriver) driver).startActivity(<appPackage>, <appActivity>);
public static void start() {
try {
((AndroidDriver) driver).startActivity("com.example.test", "com.example.LaunchApp");
} catch (Exception e) {
e.printStackTrace();
}
}
You have to enter your app package name and activity name to maximize the app.