I'm looking for some advice on how to instantiate my WebDriver driver instance in my automation framework (Selenium 3.0.1 / Java 8 / TestNG).
My goal is to handle all the instantiation code in one place, in my framework code, separated from my tests themselves, and then pass that instance around the framework.
In Ruby, I would do something like this:
./framework/driver.rb
def initialize
$driver = Selenium::WebDriver.for :firefox
# additional driver configuration
end
Then I would include the framework classes in my base test class and call my driver from there.
./tests/utilities/base_test.rb
def setup
Driver.new
end
I would then have all my tests inherit from BaseTest.
In Java, I am unfamiliar with how to achieve this with access modifiers and package structure.
So far I have something like this (taken from Selenium HQ 1):
public class Driver {
private static ChromeDriverService service;
private WebDriver driver;
{@literal @BeforeClass}
public static void createAndStartService() {
service = new ChromeDriverService.Builder()
.usingDriverExecutable(new File("path/to/my/chromedriver.exe"))
.usingAnyFreePort()
.build();
service.start();
}
{@literal @AfterClass}
public static void createAndStopService() {
service.stop();
}
{@literal @Before}
public void createDriver() {
driver = new RemoteWebDriver(service.getUrl(),
DesiredCapabilities.chrome());
}
{@literal @After}
public void quitDriver() {
driver.quit();
}
public WebDriver getDriver() {
return driver;
}
}
My question is, how can I pass this driver instance around my framework (for example, I want my Page objects to be able to use it). In Ruby, I triggered the creation of a global variable from my BaseTest. In Java, I've added the getter to return the driver instance. But this is problematic when I try to introduce TestNG annotations. For example, I want to create/teardown a driver before/after every test. I can get it to work, but is this best practice? Is there a better way?
For example, instead of using TestNG annotations to instantiate my driver, would it be better to use listeners? I've also heard about Guice and dependency injection -- is this a useful design pattern?
I've seen a number of tutorials, blog posts, articles, etc., on this topic, but I can't find what I'm after. Again, my main goal here is to handle all my driver instantiation in one place in my framework in such a way that I can pass that same driver instance around. It shouldn't matter whether it's a local ChromeDriver instance or a Remote WebDriver instance running on a grid. I need it to be clean and scalable.