0

I am a newbie in Selenium Automation.

I don't understand the concept of creating a "BaseTest" class which has one static Webdriver. I always get confused on this concept and end up creating multiple driver instances and code fails.

Can you please provide me a clear understanding of the whole concept?

public class BaseTest{

public static
      WebDriver driver = new ChromeDriver();
}

public class LoginTest extends BaseTest{

public WebDriver driver;

public LoginTest(){
     this.driver = BaseTest.driver
}
  1. Also, if I use the "BaseTest" driver instance in all Test Classes, then does it mean, that the same Chromedriver session is active throughout the test?

  2. Why do Test classes need to use one global driver instance everywhere. Does this initialise the WebDriver session or properties etc. I am confused.

1
  • Added a detailed answer, hope this helps
    – PDHide
    May 27, 2020 at 5:59

3 Answers 3

2

In your code, I think you have mixed two approaches together.

  1. Using Base Class
  2. Without Using Base Class

In Approach 1:

You don't have to assign a driver to a local variable if you are using a base class

Avoid:

public class LoginTest extends BaseTest{

public WebDriver driver;

public LoginTest(){
this.driver = BaseTest.driver
}

instead use

 public class LoginTest extends BaseTest{


    public LoginTest(){
    driver.get(url);
    }

you can use the driver variable directly as it is inherited, don't assign it to a local variable. Else page object won't work properly.

The second Approach

Here avoid base class and pass driver instance to each page object class.

public class LoginTest{

private WebDriver driver;

public LoginTest(WebDriver driver){
this.driver = driver
}

And in Test

  new LoginTest(driver)

Important:

Note that in Java everything is passed as a value but as a variable that points to a class object, will have the reference to the memory location of that object as its value, so objects will behave as they are passed as reference:

So in,

 public class LoginTest{

    private WebDriver driver;

    public LoginTest(WebDriver driver){
    this.driver = driver
    }

Whatever changes you make to this.driver or the actual driver in you test suite, will affect vice versa.

So using Base class will make it cleaner and makes novice users know that we are using the same driver instance and doesn't cause errors by mistakenly thinking changing something in the driver in the page object class doesn't affect anything else.

Consider below setup:

  public class LoginTest extends BaseTest{

  public WebDriver driver;

  public LoginTest(){
    this.driver = BaseTest.driver
    BaseTest.driver.get("https://www.google.com");
    System.out.println( BaseTest.driver.getTitle());
    System.out.println( this.driver.getTitle());      
  }

Now if you call LoginTest() you can see the code works fine and prints google as the title as the object is passed as a reference.

Now coming to your questions

Why the driver instance is static?

The driver instance need not be static unless you are accessing it as a class variable from a non-subclass

eg: TestBaseClass.driver

If you declare driver as static then you can access it from any class as a class variable of TestBaseClass.

But if you are extending all classes using TestBaseClass then driver variable will be available by default to child classes so you don't need it to be static but public.

You cannot use it as "Protected" or "Default" as it won't be available from a different package.

Also, if I use the "BaseTest" driver instance in all PageObject Classes, then does it mean, that the same Chromedriver session is active throughout the test?

Yes, you are using the same chrome driver instance throughout unless you create a new instance

eg: if you declare a driver variable in test base class as public, and inherited the base class and then initialize it from sub class as

driver = new ChromeDriver();

Then the driver variable will have the same chrome driver instance session where ever you access it from.

If you initialize and quit driver in @AfterTest and @BeforeTest then each test will have the same reference variable driver but different chrome driver instance.

Why do Test classes need to use one global driver instance everywhere. Does this initializes webdriver session or properties etc. I am confused.

We use this mainly for reporting, for instance in TestNG listeners if a test fails then in the test failure listener we can take the screenshot using the global driver variable that has the current webdriver state.

Else we have to explicitly pass the driver instance or call it statically as TestBase.driver.

What issues this could cause?

This works perfectly when you run the script in a single thread, but in parallel execution, this could cause issues so you have to make driver variable thread-safe.

0

Answering this in a more theoretical approach.

The main purpose of using a Base Class, or a Parent Class, is to take advantage of inheritance, encapsulation, clean/DRY code. These concepts are standard programming principles, so they apply to all coding, not just with test automation.

Some languages use Base Class, others use Parent Class, or even Super Class; they all mean the same thing. If you think of a parent/child relationship, the child inherits attributes from the parent. It's no different in classes. The child class will inherit functionality, data, and behavior from the parent class. This allows you to write code once, which keeps in clean (better organized) and DRY -- Don't Repeat Yourself. And if you need to, you can modify and add on to that functionality in the child class.

A class should also do one thing. In your example, a login class that only knows about the login behavior. You don't want the "login" class to know about "checkout" or "add product to cart" if this was an ecommerce application. This is encapsulation - the bundling of data, variables, properties, methods that operate on that data. It also allows you to restrict access to the data by using public, private, protected modifiers (this is dependent on which language you use, but most have them.)

To answer your specific questions, yes, if you instantiate the ChromeDriver/WebDriver (initialize it) in the Base/Parent class, you then pass a reference of the WebDriver to other classes. This allows you maintain a single WebDriver in your tests. This will help stop your tests from failing.

If you're further interested in these concepts and principles, the words in italics will you search using the standard terminology.

0

Using a static web driver is easy. That's why you see many people using it.

If all you need is a single browser instance, a static web driver is the quick and dirty way to initialize and share this object among many page model instances. The main benefit of making the web driver static, beyond ease of setting it up, is that you have one spot in your test code where the browser window is spawned and configured.

In my opinion this is not a good design. As other answers have pointed out, a static web driver object is not thread safe. You will need to completely re-plumb your test code to support parallel tests, because each test must run in its own thread. For parallel tests, you will need one web driver object per thread. Making your page models and test code "thread safe" for Selenium isn't magic. You need to utilize dependency injection.

The web driver is a dependency of a page model. Following proper object oriented design, dependencies for an object should be passed in as an argument to the constructor. This is a technique called Dependency Injection and its related buzzword, Inversion of Control.

Dependency injection requires more skill to set up. With many Java projects you need to install and configure a dependency injection framework, like the Spring IoC Container.

Pass the web driver in to a new page model as a constructor argument: new LoginPage(driver); The challenge in this case, is where to centralize the creation of the web driver. You can probably configure the Spring IoC Container to register the web driver as any other "bean" in your application, and have the Sprint IoC container create the instances of our test classes and page models. For that you will need to research how to use Spring IoC with a unit testing library like jUnit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.