Search code examples
selenium-webdrivertestngtestng-eclipse

I want to run different classes particular method from TestNG but everytime it opens a new window when i include beforeclass in each class


I want to run different classes particular method from TestNG but everytime it opens a new window when i include beforeclass in each class so i have now excluded beforeclass from add and logout classes so it can use same browser to run rest methods but its not working

The first class is of login class which is as below

public class LoginWeb {
    public WebDriver driver;
    WebDriverWait wait;
    LoginScreen loginExcel;
    @BeforeClass
    public void beforeClass (){
        System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
        driver=new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("http://10.7.1.180/views/index.html#/login");
        System.out.println(driver.getTitle());
    }

    @Test (description = "Valid Credentials!")
    public void LoginWithValidWebExcelEmailAndPass() throws IOException, BiffException  {
        loginExcel= new LoginScreen(driver);
        FileInputStream fi = new FileInputStream("D:\\Programs\\New\\Sourcesmartdata.xls");
        Workbook w = Workbook.getWorkbook(fi);
        Sheet s = w.getSheet(0);
        int z = s.getRows();
        System.out.println("no of rows------------------------:"+z);
        String email = s.getCell(0, 1).getContents();
        System.out.println("Email -----------------"+email);
        loginExcel.EnterEmail(email);
        String password= s.getCell(1, 1).getContents();
        System.out.println("Password------------------- "+password);
        loginExcel.EnterPassword(password);
        loginExcel.ClickToLogin();
        wait= new WebDriverWait(driver, 10);
        WebElement GetLogo = wait.until(ExpectedConditions.visibilityOf(loginExcel.TopRightMenu));
        String str= GetLogo.getText();
        System.out.println("Text------------"+str);
        Assert.assertEquals(str, "Source Smart");  
    }
}

The second class is of adding commodities here i have excluded beforeclass as if i include before class it opens a new window and here login script is not written

public class AddCommoditiesWeb{
    WebDriver driver;
    WebDriverWait wait;
    AddCommodities addcommodity;

    @Test (description="Add Multiple Commodities!")  
    public void AddMultipleNewCommodities () throws Exception, Exception{
        addcommodity = new AddCommodities(driver);
        addcommodity.MenuCommodities();     //click left menu to open manage commodities page
        FileInputStream fi = new FileInputStream("D:\\Programs\\New\\Sourcesmartdata.xls");
        Workbook w = Workbook.getWorkbook(fi);
        Sheet s = w.getSheet(1);
        int z=s.getRows();
        System.out.println("no of rows------------------------:"+z);
        for(int row=1; row <2; row++){
            Thread.sleep(5000);
            addcommodity.ClickAddCommodities();  // click add commodity button
            String commodityname = s.getCell(0, row).getContents();
            System.out.println("commodityname -----------------"+commodityname);
            //enterdefinecommodityTxtBox.sendKeys(commodityname);
            addcommodity.Enterdefinecommodity(commodityname);
            String grade= s.getCell(1, row).getContents();
            System.out.println("grade------------------- "+grade);
            //entergradeTxtBox.sendKeys(grade);
            String unit= s.getCell(2, row).getContents();
            System.out.println("unit------------------- "+unit);
            //enterunitTxtBox.sendKeys(unit);
            String minprice= s.getCell(3, row).getContents();
            System.out.println("min price------------------- "+minprice);
            //enterminpriceTxtBox.sendKeys(minprice);
            String maxprice= s.getCell(4, row).getContents();
            System.out.println("max price------------------- "+maxprice);
            //entermaxpriceTxtBox.sendKeys(maxprice);
            addcommodity.EnterAddCommoditiesData(grade,unit,minprice,maxprice);
        }
        wait=new WebDriverWait(driver,10);
        WebElement commodityname= wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/div[4]/div/section[2]/div[4]/d-expand-collapse[1]/div/div/div[1]/h4/a")));        
        String commoditynamejustadded= commodityname.getText();
        System.out.println("name--------------"+commoditynamejustadded);
        assertEquals(commoditynamejustadded, "Rice");
    }
}

TestNG code:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite">
  <test name="Login check">
    <classes>
      <class name="SourceSmartWeb.LoginWeb"/>
      <class name = "SourceSmartWeb.AddCommoditiesWeb">
      <methods>
      <include name="AddMultipleNewCommodities"/>
      </methods>
      </class>
      <class name ="SourceSmartWeb.LogoutWeb"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

Logout class:

public class LogoutWeb{
    WebDriver driver;
    //  @BeforeClass
    //  public void beforeClass (){
    //      System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
    //      driver=new ChromeDriver();
    //      driver.manage().window().maximize();
    //      driver.get("http://10.7.1.180/views/index.html#/login");
    //      System.out.println(driver.getTitle());
    //      super.beforeClass();
    //          
    //  }


    @Test                                                                                                       
    public void Logout() throws InterruptedException {
        LogoutScreen logout=new LogoutScreen(driver);
        logout.ClickToLogout();
    }

    @AfterClass
    public void exit(){
        driver.quit();
    }
}

What its doing is it opens the browser logins and then do nothing. How can i make it do rest of activities on same browser as if i add before class in second class it opens a new browser and then there i dont have login code. please guide


Solution

  • From what you are stating, it looks like you need to basically have a browser spawned per <test> tag and then share that browser amongst all your test classes. But you cannot make use of the @BeforeTest and @AfterTest annotations because you would need to bring in inheritance into the picture and since these methods are executed only once per <test> you will start seeing NullPointerException.

    So the idea is to basically leverage TestNG listeners for this webdriver instantiation and cleanup and have your test classes/methods just query them from within a helper method.

    Here's some sample code, that shows all of this in action.

    Here's how the listener would look like

    package com.rationaleemotions.stackoverflow.qn46239358;
    
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.remote.RemoteWebDriver;
    import org.testng.ITestContext;
    import org.testng.ITestResult;
    import org.testng.Reporter;
    import org.testng.TestListenerAdapter;
    
    public class WebdriverSpawner extends TestListenerAdapter {
        private static final String WEBDRIVER = "webdriver";
    
        @Override
        public void onStart(ITestContext testContext) {
            testContext.setAttribute(WEBDRIVER, createDriver());
        }
    
        @Override
        public void onFinish(ITestContext testContext) {
            getWebDriverFromContext(testContext).quit();
        }
    
        public static RemoteWebDriver getCurrentWebDriver() {
            ITestResult result = Reporter.getCurrentTestResult();
            if (result == null) {
                throw new IllegalStateException("Please invoke this from within a @Test annotated method");
            }
            ITestContext context = result.getTestContext();
            return getWebDriverFromContext(context);
        }
    
        private static RemoteWebDriver getWebDriverFromContext(ITestContext context) {
            Object object = context.getAttribute(WEBDRIVER);
            if (!(object instanceof RemoteWebDriver)) {
                throw new IllegalStateException("Encountered problems in retrieving the webdriver instance");
            }
            return (RemoteWebDriver) object;
    
        }
    
        private static RemoteWebDriver createDriver() {
            return new ChromeDriver();
        }
    }
    

    Here's how your test classes which now use this above listener can look like (I have intentionally kept it simple and have it open up just a URL, but if you run them you would notice a single browser opening up multiple URLs. So only one browser instance)

    package com.rationaleemotions.stackoverflow.qn46239358;
    
    import org.testng.annotations.Test;
    
    public class LoginWeb {
        @Test(description = "Valid Credentials!")
        public void LoginWithValidWebExcelEmailAndPass() {
            System.err.println("Page title : " + PageLoader.loadAndGetTitle("http://www.google.com"));
        }
    }
    
    package com.rationaleemotions.stackoverflow.qn46239358;
    
    import org.testng.annotations.Test;
    
    public class LogoutWeb {
        @Test
        public void Logout() throws InterruptedException {
            System.err.println("Page title : " + PageLoader.loadAndGetTitle("http://www.facebook.com"));
        }
    }
    
    package com.rationaleemotions.stackoverflow.qn46239358;
    
    import org.testng.annotations.Test;
    
    public class AddCommoditiesWeb {
    
        @Test(description = "Add Multiple Commodities!")
        public void AddMultipleNewCommodities() {
            System.err.println("Page title : " + PageLoader.loadAndGetTitle("http://www.yahoo.com"));
        }
    
        @Test
        public void anotherTestMethod() {
            System.err.println("Page title : " + PageLoader.loadAndGetTitle("http://www.ndtv.com"));
        }
    }
    

    The PageLoader utility class looks like this

    package com.rationaleemotions.stackoverflow.qn46239358;
    
    import org.openqa.selenium.remote.RemoteWebDriver;
    
    public final class PageLoader {
    
        private PageLoader() {
            //Utility class defeat instantiation
        }
        public static String loadAndGetTitle(String url) {
            RemoteWebDriver driver = WebdriverSpawner.getCurrentWebDriver();
            driver.get(url);
            return driver.getTitle();
        }
    }
    

    Here's how the suite xml looks like :

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
    <suite name="46216357_Suite" verbose="2">
        <listeners>
            <listener class-name="com.rationaleemotions.stackoverflow.qn46239358.WebdriverSpawner"/>
        </listeners>
    
        <test name="Login_check">
            <classes>
                <class name="com.rationaleemotions.stackoverflow.qn46239358.LoginWeb"/>
                <class name="com.rationaleemotions.stackoverflow.qn46239358.AddCommoditiesWeb">
                    <methods>
                        <include name="AddMultipleNewCommodities"/>
                    </methods>
                </class>
                <class name="com.rationaleemotions.stackoverflow.qn46239358.LogoutWeb"/>
            </classes>
        </test>
    </suite>
    

    So here none of your @Test classes invoke driver.quit() explicitly. The webdriver cleanup is managed by the listener.

    This model is going to work only when you want to run multiple tests on the same browser.

    The flip side of this would be that, you can NEVER run your @Test methods in parallel, because now all your tests are sharing the same browser.