如何从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无法正确初始化元素,后续调用元素方法就会抛出空指针。
修复步骤
- 延迟初始化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(); } }
- 确认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
相关产品推荐
相关产品推荐

