You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Steps测试类为WebElement赋值?空指针异常排查

问题描述

我想把WebElement仅放在Page Object类中,但在Steps测试类调用实例时无法使用这些元素。XPath是正确的,直接在Steps类里调用元素是有效的。我希望能在Steps类中直接调用并处理,比如:loginScreen.loginUser.sendKeys("userX")。

代码片段

PageObject类(LoginScreen.java)

import com.test.core.BasePage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;


public class LoginScreen extends BasePage {

    public String baseUrl = "https://10.125.103.235:6501/opt/security_check";

    @FindBy(xpath = "//input[@id='userId']")
    public WebElement loginUser;

    @FindBy(xpath = "//input[@id='password']")
    public WebElement loginPassword;

    @FindBy(xpath = "//input[@id='loginButton']")
    public WebElement loginEnter;

    
    public LoginScreen(WebDriver driver) {
        super(driver);
        PageFactory.initElements(driver, this);
    }

    public void set_user(String user){
        loginUser.sendKeys(user);
    }

    public void set_password(String password){
        loginPassword.sendKeys(password);
    }

    public void clickOnEnter(){
        loginEnter.click();
    }

}

Steps类(LoginSteps.java)

import com.test.core.BaseTest;
import com.test.screens.LoginScreen;
import io.cucumber.java.en.And;
import io.cucumber.java.pt.Dado;

public class LoginSteps extends BaseTest{

    LoginScreen loginScreen = new LoginScreen(getDriver());

    @Dado("que o usuario acesse o PSRM")
    public void browserOpenPsrm() {
        loginScreen.driver.manage().window().maximize();
        loginScreen.driver.get(loginScreen.baseUrl);
    }

    @And("realiza o login com o USER: {string} e SENHA: {string}")
    public void loginSuccess(String user, String senha) {
        loginScreen.set_user(user);
        loginScreen.set_password(senha);
        loginScreen.clickOnEnter();

    }
}

错误信息

java.lang.NullPointerException
    at org.openqa.selenium.support.pagefactory.DefaultElementLocator.findElement(DefaultElementLocator.java:70)
    at org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler.invoke(LocatingElementHandler.java:39)
    at com.sun.proxy.$Proxy19.sendKeys(Unknown Source)
    at com.test.screens.LoginScreen.set_user(LoginScreen.java:32)
    at com.test.stepdefinitions.LoginSteps.loginSuccess(LoginSteps.java:23)
解决方案

空指针的核心原因是初始化LoginScreen时,getDriver()返回的是null。Cucumber实例化Steps类时,BaseTest中的WebDriver还没完成初始化,导致传给LoginScreen的driver为null,PageFactory无法正确初始化元素,后续调用元素方法就会抛出空指针。

修复步骤

  1. 延迟初始化LoginScreen
    不要在Steps类的成员变量位置直接实例化LoginScreen,而是在第一个执行的步骤方法(比如打开浏览器的方法)中初始化,确保此时driver已经就绪:
import com.test.core.BaseTest;
import com.test.screens.LoginScreen;
import io.cucumber.java.en.And;
import io.cucumber.java.pt.Dado;

public class LoginSteps extends BaseTest{

    LoginScreen loginScreen; // 先声明,不初始化

    @Dado("que o usuario acesse o PSRM")
    public void browserOpenPsrm() {
        loginScreen = new LoginScreen(getDriver()); // 此处初始化,确保driver已就绪
        loginScreen.driver.manage().window().maximize();
        loginScreen.driver.get(loginScreen.baseUrl);
    }

    @And("realiza o login com o USER: {string} e SENHA: {string}")
    public void loginSuccess(String user, String senha) {
        // 现在可以直接调用元素
        loginScreen.loginUser.sendKeys(user);
        loginScreen.loginPassword.sendKeys(senha);
        loginScreen.loginEnter.click();
        
        // 或者继续使用封装好的方法
        // loginScreen.set_user(user);
        // loginScreen.set_password(senha);
        // loginScreen.clickOnEnter();
    }
}
  1. 确认BaseTest的driver初始化时机
    确保BaseTest中的getDriver()方法被调用时,WebDriver已经完成初始化,建议在Cucumber的@Before钩子中初始化driver:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.Before;

public class BaseTest {
    private WebDriver driver;

    @Before
    public void setup() {
        // 在所有Steps执行前初始化driver
        System.setProperty("webdriver.chrome.driver", "你的chromedriver路径");
        driver = new ChromeDriver();
    }

    public WebDriver getDriver() {
        return driver;
    }
}

额外优化建议

虽然你希望直接调用WebElement,但从Page Object模式的设计原则来说,建议不要将WebElement设为public暴露,而是通过封装的方法操作元素(比如你写的set_user、set_password),这样后续页面元素变化时,只需要修改Page类,无需改动Steps类,降低代码耦合。如果一定要直接调用元素,确保初始化逻辑正确即可。

内容的提问来源于stack exchange,提问作者Allison

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:40:29