如何避免从ThreadLocal向测试类传递WebDriver时触发NullPointerException
问题场景
在BaseTest类中通过ThreadLocal实现线程安全的WebDriver,继承该类的测试类T001_LoginTests_Check在创建HomePage_Check页面对象时,通过构造方法传入getDriver()获取的驱动,触发NullPointerException。
原因分析
测试类中HomePage_Check homePageCheck = new HomePage_Check(getDriver());属于类级变量初始化,执行时机早于TestNG的@BeforeSuite注解方法。而ThreadLocal中的WebDriver实例是在@BeforeSuite修饰的setUp()方法里通过setDriver(driver)存入的,此时getDriver()返回null,导致页面对象的driver成员变量为空,后续调用driver.getTitle()时触发空指针。
解决方案
将页面对象的初始化时机延后到WebDriver实例创建完成之后,比如使用TestNG的@BeforeMethod注解方法:
修改后的测试类T001_LoginTests_Check代码
package tests; import base.BaseTest; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import pages.HomePage_Check; public class T001_LoginTests_Check extends BaseTest { HomePage_Check homePageCheck; @BeforeMethod public void initPageObjects() { // 此时@BeforeSuite已执行,ThreadLocal中已有WebDriver实例 homePageCheck = new HomePage_Check(getDriver()); } @Test public void pageTitleTest(){ System.out.println("[?] Called from test class -> " + driver); homePageCheck.getPageTitle(); } }
其他可选优化(可选)
如果希望简化页面对象的创建,也可以让页面对象直接调用BaseTest.getDriver(),无需构造传参:
修改HomePage_Check类:
package pages; import base.BaseTest; import org.openqa.selenium.WebDriver; public class HomePage_Check { public WebDriver driver; public HomePage_Check(){ this.driver = BaseTest.getDriver(); } public void getPageTitle(){ System.out.println(driver.getTitle()); } }
这种方式下,测试类可直接初始化页面对象:
HomePage_Check homePageCheck = new HomePage_Check();
验证效果
修改后,@BeforeMethod会在每个@Test方法执行前运行,此时WebDriver已完成初始化并存入ThreadLocal,getDriver()能返回有效实例,页面对象的driver成员变量不再为空,调用getTitle()不会触发空指针。
内容的提问来源于stack exchange,提问作者Aliul Islam Abir

