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

使用@BeforeClass初始化Appium AndroidDriver时遇NullPointerException求助

问题:Appium+TestNG初始化驱动后页面对象报NullPointerException

在使用TestNG+Appium做自动化测试时,出现以下问题:

  • 通过@BeforeSuite启动Appium服务
  • Base类中使用@BeforeClass注解的静态方法setDriver初始化AndroidDriver,通过getDriver()方法获取驱动
  • 测试类继承Base后,在成员变量处调用getDriver()初始化页面对象
  • 运行测试方法时抛出NullPointerException,提示Cannot invoke "org.openqa.selenium.SearchContext.findElement(org.openqa.selenium.By)" because "this.searchContext" is null

Base类代码

package setup;

import java.net.URL;
import java.time.Duration;

import org.apache.commons.lang3.RandomStringUtils;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;

import java.io.IOException;
import java.net.MalformedURLException;
import io.appium.java_client.android.AndroidDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
import net.bytebuddy.utility.RandomString;

public class Base {
    String deviceIp = "192.148.31.156";

    Runtime runtime = Runtime.getRuntime();
    public static AndroidDriver driverA;
    static URL appiumURL;
    static DesiredCapabilities capabilities = new DesiredCapabilities();

    @BeforeSuite
    public void startServer() {
        try {
            runtime.exec("cmd.exe /c start cmd.exe /k adb connect " + deviceIp + "");
            runtime.exec("cmd.exe /c start cmd.exe /k appium -a 127.0.0.1 -p 4723");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @BeforeClass
    public static AndroidDriver setDriver() {

        capabilities.setCapability("automationName", "Appium");
        capabilities.setCapability("platformName", "Android");
        capabilities.setCapability("platformVersion", "12.0");
        capabilities.setCapability("deviceName", "192");
        capabilities.setCapability("unlockKey", "934448");
        capabilities.setCapability("app", "C:\\Users\\DELL\\Desktop\\APK files\\YEO App Android\\app.apk");
        capabilities.setCapability("autoGrantPermissions", "true");

        try {
            appiumURL = new URL("http://127.0.0.1:4733/wd/hub");
            driverA = new AndroidDriver(appiumURL, capabilities);
            // driverA.manage().timeouts().implicitlyWait(10, nulls);
            driverA.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        return driverA;
    }

    @AfterSuite
    public void stopServer() {
        try {
            runtime.exec("taskkill /F /IM node.exe");
            runtime.exec("taskkill /F /IM cmd.exe");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static AndroidDriver getDriver() {
        // this.setDriver();
        return driverA;
    }

}

测试类代码

package testcases;
import org.testng.annotations.Test;

import Resources.RuntimeHandler;

import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;
import pageFactories.LaunchScreen;
import pageFactories.MessagesScreen;
import pageFactories.SettingsScreen;
import pageFactories.YEOLockScreen;
import setup.Base;

import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import io.appium.java_client.android.AndroidDriver;

public class TC_LoginToYEO extends Base {   
    LaunchScreen launch = new LaunchScreen(getDriver());
    YEOLockScreen lock = new YEOLockScreen(getDriver());
    SettingsScreen settings = new SettingsScreen(getDriver());
    MessagesScreen ms = new MessagesScreen(getDriver());

    @Test(priority = 0)
    public void login_To_YEO() {
        launch.select_Country_Code("India");
        launch.login("891", "3");
    }
}

报错信息

java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.SearchContext.findElement(org.openqa.selenium.By)" because "this.searchContext" is null
    at org.openqa.selenium.support.pagefactory.DefaultElementLocator.findElement(DefaultElementLocator.java:70)
    at org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler.invoke(LocatingElementHandler.java:39)
    at jdk.proxy2/jdk.proxy2.$Proxy12.click(Unknown Source)
    at pageFactories.LaunchScreen.nav_To_LoginPage(LaunchScreen.java:62)
    at pageFactories.LaunchScreen.select_Country_Code(LaunchScreen.java:67)
    at testcases.TC_LoginToYEO.login_To_YEO(TC_LoginToYEO.java:32)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.testng.internal.invokers.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:139)
    at org.testng.internal.invokers.TestInvoker.invokeMethod(TestInvoker.java:677)
    at org.testng.internal.invokers.TestInvoker.invokeTestMethod(TestInvoker.java:221)
    at org.testng.internal.invokers.MethodRunner.runInSequence(MethodRunner.java:50)
    at org.testng.internal.invokers.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:962)
    at org.testng.internal.invokers.TestInvoker.invokeTestMethods(TestInvoker.java:194)
    at org.testng.internal.invokers.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:148)
    at org.testng.internal.invokers.TestMethodWorker.run(TestMethodWorker.java:128)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.testng.TestRunner.privateRun(TestRunner.java:806)
    at org.testng.TestRunner.run(TestRunner.java:601)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:433)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:427)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:387)
    at org.testng.SuiteRunner.run(SuiteRunner.java:330)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:95)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1256)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1176)
    at org.testng.TestNG.runSuites(TestNG.java:1099)
    at org.testng.TestNG.run(TestNG.java:1067)
    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)

解决方案

1. 修复TestNG注解方法的静态修饰符问题

TestNG不会正确执行带有static修饰的@BeforeClass方法,导致driverA始终未初始化。修改Base类的setDriver方法,去掉static:

@BeforeClass
public AndroidDriver setDriver() { // 移除static修饰符
    capabilities.setCapability("automationName", "Appium");
    capabilities.setCapability("platformName", "Android");
    capabilities.setCapability("platformVersion", "12.0");
    capabilities.setCapability("deviceName", "192");
    capabilities.setCapability("unlockKey", "934448");
    capabilities.setCapability("app", "C:\\Users\\DELL\\Desktop\\APK files\\YEO App Android\\app.apk");
    capabilities.setCapability("autoGrantPermissions", "true");

    try {
        appiumURL = new URL("http://127.0.0.1:4723/wd/hub"); // 同时修正端口
        driverA = new AndroidDriver(appiumURL, capabilities);
        driverA.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }

    return driverA;
}

同时更新getDriver方法,去掉static:

public AndroidDriver getDriver() {
    return driverA;
}

2. 延迟页面对象初始化时机

测试类中成员变量的初始化时机早于@BeforeClass方法执行,此时getDriver()返回null,导致页面对象的searchContext为空。需将页面对象初始化放在@BeforeClass方法中:

public class TC_LoginToYEO extends Base {   
    LaunchScreen launch;
    YEOLockScreen lock;
    SettingsScreen settings;
    MessagesScreen ms;

    @BeforeClass
    public void initPageObjects() {
        launch = new LaunchScreen(getDriver());
        lock = new YEOLockScreen(getDriver());
        settings = new SettingsScreen(getDriver());
        ms = new MessagesScreen(getDriver());
    }

    @Test(priority = 0)
    public void login_To_YEO() {
        launch.select_Country_Code("India");
        launch.login("891", "3");
    }
}

3. 修正Appium服务端口不一致问题

Base类中启动Appium服务用的是端口4723,但初始化驱动时用的是4733,端口不匹配会导致驱动初始化失败,需将URL中的端口改为4723:

appiumURL = new URL("http://127.0.0.1:4723/wd/hub");

4. 优化Appium服务启动的可靠性

直接用Runtime.exec启动服务可能存在服务未完全就绪就初始化驱动的问题,建议使用AppiumServiceBuilder来管理服务:

import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;

@BeforeSuite
public void startServer() {
    // 构建并启动Appium服务
    AppiumDriverLocalService appiumService = new AppiumServiceBuilder()
            .withIPAddress("127.0.0.1")
            .usingPort(4723)
            .build();
    appiumService.start();

    // 连接设备
    try {
        runtime.exec("adb connect " + deviceIp);
        Thread.sleep(2000); // 等待设备连接完成
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

@AfterSuite
public void stopServer() {
    // 停止Appium服务
    AppiumDriverLocalService appiumService = AppiumDriverLocalService.getService();
    if (appiumService != null && appiumService.isRunning()) {
        appiumService.stop();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 22:30:53