How to pass single instance of WebDriver between T

2019-06-14 04:18发布

问题:

I couldnt find a difinitive answer to this anywhere on the net.

I have multiple TestNg classes to run tests, BrowserFunctions, Login, Search, Filter (testing Amazon uk for practice). I also have a BrowserLauncher class that returns the appropriate webdriver based on browser name, and a testng.xml file.

BrowserFunctions.java

public class BrowserFunctions {

BrowserLauncher bl = new BrowserLauncher();
WebDriver driver;
StringBuilder sb = new StringBuilder();

@BeforeSuite
public void initialioseBrowser() {
    driver = bl.launchBrowser("Firefox");
}

@Parameters({ "URL" })
@BeforeSuite
public void invokeURL(String URL) {
    driver.get(URL);
}

@AfterSuite
public void closeBrowser() {
    driver.close();
}

Login.java

public class Login {

BrowserLauncher bl = new BrowserLauncher();
WebDriver driver;
StringBuilder sb = new StringBuilder();

@Parameters({ "email", "password" })
@Test
public void logInTest(String email, String passowrd) {
    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKsignInCTA), "Sign in CTA visible");
    CommonFunctions.clickButton(driver, PageElements.amzUKsignInCTA);
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKEmailField), "Email field visible");
    CommonFunctions.inputToField(driver, PageElements.amzUKEmailField, email);
    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKPasswordField),
            "Password field visible");
    CommonFunctions.inputToField(driver, PageElements.amzUKPasswordField, passowrd);
    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKSignInButton),
            "Sign in button visible");
    CommonFunctions.clickButton(driver, PageElements.amzUKSignInButton);
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    Assert.assertEquals(driver.getCurrentUrl(), "https://www.amazon.co.uk/?ref_=nav_ya_signin&");
}

Search.java

public class Search {

BrowserLauncher bl = new BrowserLauncher();
WebDriver driver;
StringBuilder sb = new StringBuilder();

@Parameters({ "searchTerm" })
@Test
public void searchTest(String searchTerm) {
    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKSearchField),
            "Search field visible");
    CommonFunctions.inputToField(driver, PageElements.amzUKSearchField, searchTerm);
    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKSearchButton),
            "Search button visible");
    CommonFunctions.clickButton(driver, PageElements.amzUKSearchButton);
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKResultContainer),
            "Results container visible");
    if (driver.findElements(PageElements.amzUKResultContainer).size() > 0) {
        List<WebElement> resultContainerList = driver.findElements(PageElements.amzUKResultContainer);
        for (WebElement w : resultContainerList) {
            if (w.findElements(PageElements.amzUKResultTitle).size() > 0) {
                if (w.findElement(PageElements.amzUKResultTitle).getText().contains(searchTerm)) {
                } else {
                    sb.append(w.findElement(PageElements.amzUKResultTitle).getText() + " does not contain"
                            + searchTerm + "\n");
                }
            }
            Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKResultImage),
                    "Result image visible");
            if (w.findElements(PageElements.amzUKResultImage).size() > 0) {
            } else {
                sb.append(w.findElement(PageElements.amzUKResultTitle).getText() 
                        + " does not contain an image\n");
            }
            Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKResultPrice),
                    "Result price visible");
            if (w.findElements(PageElements.amzUKResultPrice).size() > 0) {
                if (w.findElement(PageElements.amzUKResultPrice).getText().contains("£")) {
                } else {
                    sb.append(w.findElement(PageElements.amzUKResultTitle).getText() 
                            + " does not contain a price\n");
                }
            }
        }
    }
    System.out.println("searchTest(" + searchTerm + ") Failures:\n" + sb.toString());
}

Filter.java public class Filter {

BrowserLauncher bl = new BrowserLauncher();
WebDriver driver;
StringBuilder sb = new StringBuilder();

@Test
public void filterTest() {
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    List<String> filterOptionsList = new ArrayList<String>();

    sb.append(CommonFunctions.clickButton(driver, PageElements.amzUKFilterSeeMore));

    Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKFilterOptions),
            "Filter options visible");
    for (int i = 0; i < driver.findElements(PageElements.amzUKFilterOptions).size(); i++) {
        filterOptionsList.add(driver.findElements(PageElements.amzUKFilterOptions).get(i).getText());
    }

    for (String s : filterOptionsList) {
        Assert.assertTrue(CommonFunctions.checkVisibility(driver, By.partialLinkText(s)), "" 
                + s + " link visible");
        if (driver.findElements(By.partialLinkText(s)).size() > 0) {
            driver.findElement(By.partialLinkText(s)).click();
        }else {
            sb.append("Link " + s + " not visible");
            continue;
        }
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKFilterAnyCategory),
                "\"Any Category\" button visible");
        CommonFunctions.clickButton(driver, PageElements.amzUKFilterAnyCategory);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        sb.append(CommonFunctions.clickButton(driver, PageElements.amzUKFilterSeeMore));
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }
    System.out.println("filterTest Failures:\n" + sb.toString());
}

BrowserLauncher.java

public WebDriver launchBrowser(String BrowserName) {
    if(BrowserName.equalsIgnoreCase("Firefox")) {
        driver = new FirefoxDriver();
        driver.manage().window().maximize();
    } else if(BrowserName.equalsIgnoreCase("IE")) {
        DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer();
        capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
        capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
        capabilities.setCapability(InternetExplorerDriver.INITIAL_BROWSER_URL, "");
        System.setProperty("webdriver.ie.driver", "C:\\Eclipse EE x86 Workspace\\ResidentAdvisorLabels\\IEDriverServer.exe");
        driver = new InternetExplorerDriver(capabilities);
        driver.get("javascript:document.getElementById('overridelink').click();");
    } else if(BrowserName.equalsIgnoreCase("Chrome")) {
        ChromeOptions op = new ChromeOptions();
        op.addArguments("--user-data-dir=C:\\Users\\Bernard\\Desktop\\Selenium Data");
        op.addArguments("--start-maximized");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
        System.setProperty("webdriver.chrome.driver", "C:\\Eclipse EE x86 Workspace\\ResidentAdvisorLabels\\chromedriver.exe");
        driver = new ChromeDriver(op);
        driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
    } else if(BrowserName.equalsIgnoreCase("PhantomJS")) {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("takesScreenshot", false);
        String d = "\\";
        capabilities.setCapability("phantomjs.binary.path", "C:"+d+"Eclipse EE x86 Workspace"+d+"phantomjs-2.0.0-windows"+d+"bin"+d+"phantomjs.exe");
        capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
        capabilities.setCapability("load-images", false);
        driver = new PhantomJSDriver(capabilities);
        driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
    }

    return driver;
}

testng.xml

<suite name="Suite1" verbose="1">
<parameter name="searchTerm" value="Selenium Webdriver" />
<parameter name="URL" value="Http://www.amazon.co.uk" />
<parameter name="email" value="scrubbed" />
<parameter name="password" value="scrubbed" />
<test name="AmazonUKTesting">
    <classes>
        <class name="tests.amazonUKTests.BrowserFunctions" />
        <class name="tests.amazonUKTests.Login" />
        <class name="tests.amazonUKTests.Search" />
        <class name="tests.amazonUKTests.Filter" />
    </classes>
</test>

My problem is that i cannot seem to be able to pass the WebDriver that is returned to the BrowserFunctions.java class on to the other classes in my test suite without having to create a new instance of WebDriver in each java file. I am looking to open the browser, open the URL, then run the 3 tests one after another in the same browser window, and have the browser close when done.

回答1:

Yes, this is possible to use the same driver instance across multiple classes without closing the browser window each time. Sorry didn't get much time to set this up for your code. But here I've prepared a quick example for you. This might be of some help for sure.

Use BrowserFunctions.java as a Base class.

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.*;

public class BrowserFunctions {
public static WebDriver driver;
StringBuilder sb = new StringBuilder();

@BeforeSuite
public void initialioseBrowser() {
driver = new FirefoxDriver();
}

@AfterSuite
public void closeBrowser() {
driver.quit();
}
}

Inherit this class in your other two classes: Example, Google.java

import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.*;

public class Google extends BrowserFunctions{

@Test
public void google() throws InterruptedException{
driver.get("https://www.google.com");

WebDriverWait wait = new WebDriverWait(driver, 30); 
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("lst-ib"))); 

driver.findElement(By.id("lst-ib")).sendKeys("Bello");
Thread.sleep(5000);

}
}

and FB.java

import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.*;

public class FB extends BrowserFunctions{

@Test
public void google() throws InterruptedException{

driver.get("https://www.fb.com");
WebDriverWait wait = new WebDriverWait(driver, 30); 

Thread.sleep(5000);
System.out.println("Title"+driver.getTitle());
System.out.println("URL"+driver.getCurrentUrl());

wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("day"))); 

Select day= new Select(driver.findElement(By.id("day")));
day.selectByVisibleText("10");

Select month= new Select(driver.findElement(By.id("month")));
month.selectByVisibleText("Jan");

Select year= new Select(driver.findElement(By.id("year")));
year.selectByVisibleText("1950");


}
}

and Your Testng.xml will be somewhat like this:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite1" verbose="1">
<test name="Test">
<classes>
    <class name="Google" />
    <class name="FB" />
</classes>
</test>
</suite>

Try this out once on your system and then try to something similar to this using your code. Should help! and Sorry for using Thread.sleep at too many places, you should not be using it too often. :)



回答2:

You can extend a base class as others have suggested or you can use TestNG Guice dependency injection. e.g.:

TestModule.class

import com.google.inject.Binder;
import com.google.inject.Module;

public class TestModule implements Module {
    @Override
    public void configure(Binder binder) {
        BrowserLauncher bl = new BrowserLauncher();
        WebDriver driver = bl.launchBrowser("Firefox");
        binder.bind(WebDriver.class).toInstance(driver);
    }
}

BrowserFunctions.java

import com.google.inject.Inject;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Guice;
import org.testng.annotations.Parameters;

@Guice(modules = {TestModule.class})
public class BrowserFunctions {
    @Inject
    WebDriver driver;

    @Parameters({ "URL" })
    @BeforeSuite
    public void invokeURL(String URL) {
        driver.get(URL);
    }

    @AfterSuite
    public void closeBrowser() {
        driver.close();
    }
}

Login.java

import com.google.inject.Inject;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

import java.util.concurrent.TimeUnit;

@Guice(modules = {TestModule.class})
public class Login {
    @Inject
    WebDriver driver;
    StringBuilder sb = new StringBuilder();

    @Parameters({ "email", "password" })
    @Test
    public void logInTest(String email, String passowrd) {
        Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKsignInCTA), "Sign in CTA visible");
        CommonFunctions.clickButton(driver, PageElements.amzUKsignInCTA);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKEmailField), "Email field visible");
        CommonFunctions.inputToField(driver, PageElements.amzUKEmailField, email);
        Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKPasswordField),
                "Password field visible");
        CommonFunctions.inputToField(driver, PageElements.amzUKPasswordField, passowrd);
        Assert.assertTrue(CommonFunctions.checkVisibility(driver, PageElements.amzUKSignInButton),
                "Sign in button visible");
        CommonFunctions.clickButton(driver, PageElements.amzUKSignInButton);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        Assert.assertEquals(driver.getCurrentUrl(), "https://www.amazon.co.uk/?ref_=nav_ya_signin&");
    }
}

etc.



回答3:

we can achieve this by extending BrowserFunctions to all other classes except BrowserLauncher.java.

in BrowserFunctions do below changes.

 public static WebDriver driver; //instead of WebDriver driver;
 //you can make only one before suite in that launchBrowser and navigate URL

extends this class to other classes except BrowserLauncher.java and delete "WebDriver driver;". below is ex for one

public class Login extends BrowserFunctions{

 //WebDriver driver; //just commented you can delete this.

Thank You, murali



回答4:

Just change your WebDriver Declaration to static

and also change the structure of your testng.xml as given in below example

<suite name="SuiteName">
 <test name="Test1">
  <classes>
   <class name="Class1" />
  </classes>
 </test>
 <test name="Test2">
  <classes>
   <class name="Class2" />
  </classes>
 </test>
</suite>


回答5:

My suggestion is slightly different than others. I would create (and I have for my project) a data provider class that stores the web driver instance (as well as other meaningful data). Then, when needed, just call the data provider and ask for the web driver. For example:

public class MyDataProvider {
  public static WebDriver driver;
  ...
 }

public class BrowserFunctions {
  StringBuilder sb = new StringBuilder();

  @BeforeSuite
  public void initialioseBrowser() {
    MyDataProvider.driver = new FirefoxDriver();
  }

  @AfterSuite
  public void closeBrowser() {
    MyDataProvider.driver.quit();
  }
}

The reasons for having this data provider holding the web driver's instance should be somewhat obvious. Two reasons come to mind:

  1. To have a centralized data hub from where all your meaningful data can be obtained. Doing this eliminate needing to have all these object references in your test classes.
  2. Separation of concerns. Your test classes should focus on aspects of testing. Your data provider should concern itself with managing data.

I also like @mfulton26 answer about using TestNG Guice. So I am going to look into it.