-3

Why is below happening and how can i use this under the EnglishHomepage ?

my code(not working) :

public class EnglishHomepage {

    WebDriver driver = null; 

    public Actions action = new Actions(driver);

    By login_button = By.xpath("//*[@id=\"wrapper\"]/div[1]/header/div[2]/div[1]/div/a[15]");


    //constructor of EnglishHomepage
    public EnglishHomepage (WebDriver driver) {

        this.driver = driver; 
    }

    public void clickFogotPassword() {
        driver.findElement(login_button ).click();
    }


    public void clickDropdownValue() {

        action.doubleClick(driver.findElement(xpath2)).perform();   

    }
}

code (working)

public class EnglishHomepage {

    WebDriver driver = null; 

    By login_button = By.xpath("//*[@id=\"wrapper\"]/div[1]/header/div[2]/div[1]/div/a[15]");


    //constructor of EnglishHomepage
    public EnglishHomepage (WebDriver driver) {

        this.driver = driver; 
    }

    public void clickFogotPassword() {
        driver.findElement(login_button ).click();
    }


    public void clickDropdownValue() {

        **Actions action = new Actions(driver);**
        action.doubleClick(driver.findElement(xpath2)).perform();   

    }
}

I can use public Actions action = new Actions(driver); under the clickDropdownValue method and test is working fine as expected.

however,

when i move public Actions action = new Actions(driver); under the class, could see java.lang.NullPointerException.

exception

at java.util.Objects.requireNonNull(Objects.java:203) at org.openqa.selenium.interactions.Actions.(Actions.java:65) at pages.EnglishHomepage.(EnglishHomepage.java:12) at testcases.Tc4_Market_status.click(Tc4_Market_status.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:133) at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:584) at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:172) at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46) at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:804) at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:145) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128) at java.util.ArrayList.forEach(ArrayList.java:1257) at org.testng.TestRunner.privateRun(TestRunner.java:770) at org.testng.TestRunner.run(TestRunner.java:591) at org.testng.SuiteRunner.runTest(SuiteRunner.java:402) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:396) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:355) at org.testng.SuiteRunner.run(SuiteRunner.java:304) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1180) at org.testng.TestNG.runSuitesLocally(TestNG.java:1102) at org.testng.TestNG.runSuites(TestNG.java:1032) at org.testng.TestNG.run(TestNG.java:1000) at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)

CookieMan
  • 71
  • 8

2 Answers2

3

If new Actions(driver) is locate above the constructor, it is executed before the constructor body, i.e. the value of driver will still be null.

If new Actions(driver) is locate below the constructor, it is executed after the constructor body, i.e. the value of driver will be the value passed to the constructor.

Recommendation: In a field initializer, never use another field that is not fully initialized in its own initializer, and never use a field declared later.

The correct way to do this is to initialize the field in the constructor too, where the value is available.

WebDriver driver; // No need to initialize to null, it's the default

public Actions action; // Don't initialize here

public EnglishHomepage (WebDriver driver) {
    this.driver = driver; 
    this.action = new Actions(driver);
}

UPDATE

Actually, moving the field declaration down shouldn't have worked, according to the Java Language Specification, section 12.5. Creation of New Class Instances, which specifies this order of initialization (para-phrased):

Allocate memory and call constructor, which is evaluated as follows:

  • If this constructor begins with this(...), call the other constructor. Process that constructor invocation recursively using these same steps.

  • Otherwise, call the superclass constructor, either as specified with a super(...) statement, or implicitly call the no-arg superclass constructor.

  • Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class.

  • Execute the rest of the body of this constructor.

As can be seen, the constructor body (except this(...) and super(...)) is always executed last, according to the specification, so moving the field declaration down below the constructor shouldn't have changed the fact that the driver field is null when the action field is initialized.

The recommendation given above is the way to go.

Community
  • 1
  • 1
Andreas
  • 154,647
  • 11
  • 152
  • 247
1

when you are using below code.

WebDriver driver; 

public Actions action=new Actions(driver);

it will for sure give null pointer exception because you have assigned driver as null. so if you want to use driver you can use below code.

WebDriver driver; 

public Actions action;

public EnglishHomepage (WebDriver driver) {

    this.driver = driver; 
    this.action = new Actions(this.driver); // now driver is initialized so it will not give null pointer exception. always assign value under constructor. when you are assigning value inline so current value is **null** 

}
Negi Rox
  • 3,828
  • 1
  • 11
  • 18