Appium, Java & Testng - 找到 NullPointerException 的原因
Appium, Java & Testng - find the reason for a NullPointerException
我在 Appium 和模拟器启动之前收到 NullPointerException
。因此,尝试通过代码中的 sysout
行进行调试根本没有帮助。
如果有人有什么建议,请发送给我,因为我快要疯了!
我的依赖项:
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.9</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.0.0-beta3</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
我的 Hooks class:
package MA.test;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;
import java.net.MalformedURLException;
import java.net.URL;
public class Hooks {
public AppiumDriver driver;
public AppiumDriverLocalService service;
@Parameters({"platformVersion", "emulatorNumber", "deviceName", "port"})
@BeforeTest(alwaysRun = true)
public void startAppiumServer(String platformVersion, String emulatorNumber, String deviceName, String port) throws InterruptedException, MalformedURLException {
System.out.println("\n ABC");
service = new AppiumServiceBuilder()
.usingPort(Integer.valueOf(port))
.build();
service.start();
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
caps.setCapability(MobileCapabilityType.DEVICE_NAME, emulatorNumber);
caps.setCapability(AndroidMobileCapabilityType.AVD, deviceName);
caps.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
caps.setCapability(MobileCapabilityType.APPLICATION_NAME, "Name");
caps.setCapability(MobileCapabilityType.APPIUM_VERSION, "1.14.0");
caps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "activity");
caps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "package");
caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, "UiAutomator2");
driver = new AndroidDriver<MobileElement>(new URL("http://0.0.0.0:" + port + "/wd/hub"), caps);
System.out.println("\n Appium server: " + service.getUrl());
Thread.sleep(2000);
}
@AfterTest
public void teardown() {
service.stop();
driver.quit();
driver.closeApp();
System.out.println("\n Test quit");
}
}
我的 TestRunner class:
package MA.steps;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.AbstractTestNGCucumberTests;
@CucumberOptions(
plugin = {"pretty", "html:target/cucumber-reports"}
, monochrome = true
, features = "src/test/java/feature"
, tags = "@Login"
)
public class TestRunner extends AbstractTestNGCucumberTests {
}
我的 testng.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Android Parallel Execution" parallel="tests" thread-count="2" verbose="7">
<test name="Device1">
<parameter name="platformVersion" value="9.0"/>
<parameter name="emulatorNumber" value="emulator-5554"/>
<parameter name="deviceName" value="Android9_Nexus"/>
<parameter name="port" value="4723"/>
<classes>
<class name="MA.steps.TestRunner"/>
</classes>
</test>
</suite>
我收到以下错误:
java.lang.NullPointerException
at screens.myAccountOverviewScreen.logoutAccount(myAccountOverviewScreen.java:104)
它指向以下代码行:
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
这是第一次在我的测试中调用 driver
,但令我困惑的是它甚至没有启动 appium 或启动模拟器就抛出 nullpointerexception
。
问题出在你的测试代码上
您创建了套件 xml 文件以仅包含您的 TestRunner
class。但是整个 appium 实例化逻辑都卡在 Hooks
class 中,它通过 TestNG 配置注释 @BeforeTest
和 @AfterTest
来完成。但是这个 class 既不包含在您的套件中,也不包含您的测试 class (TestRunner
) 扩展它。因此,您的配置不会被调用,从而导致 AppiumDriver
对象的空值。
要解决此问题,您可以执行以下操作之一:
- 编辑您的套件 xml 文件并在其中包含
Hooks
class。 (或)
- 构建一个实现
IInvokedMethodListener
的 TestNG 侦听器并将您的驱动程序实例化到其 beforeInvocation
我在 Appium 和模拟器启动之前收到 NullPointerException
。因此,尝试通过代码中的 sysout
行进行调试根本没有帮助。
如果有人有什么建议,请发送给我,因为我快要疯了!
我的依赖项:
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.9</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.0.0-beta3</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
我的 Hooks class:
package MA.test;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;
import java.net.MalformedURLException;
import java.net.URL;
public class Hooks {
public AppiumDriver driver;
public AppiumDriverLocalService service;
@Parameters({"platformVersion", "emulatorNumber", "deviceName", "port"})
@BeforeTest(alwaysRun = true)
public void startAppiumServer(String platformVersion, String emulatorNumber, String deviceName, String port) throws InterruptedException, MalformedURLException {
System.out.println("\n ABC");
service = new AppiumServiceBuilder()
.usingPort(Integer.valueOf(port))
.build();
service.start();
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
caps.setCapability(MobileCapabilityType.DEVICE_NAME, emulatorNumber);
caps.setCapability(AndroidMobileCapabilityType.AVD, deviceName);
caps.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
caps.setCapability(MobileCapabilityType.APPLICATION_NAME, "Name");
caps.setCapability(MobileCapabilityType.APPIUM_VERSION, "1.14.0");
caps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "activity");
caps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "package");
caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, "UiAutomator2");
driver = new AndroidDriver<MobileElement>(new URL("http://0.0.0.0:" + port + "/wd/hub"), caps);
System.out.println("\n Appium server: " + service.getUrl());
Thread.sleep(2000);
}
@AfterTest
public void teardown() {
service.stop();
driver.quit();
driver.closeApp();
System.out.println("\n Test quit");
}
}
我的 TestRunner class:
package MA.steps;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.AbstractTestNGCucumberTests;
@CucumberOptions(
plugin = {"pretty", "html:target/cucumber-reports"}
, monochrome = true
, features = "src/test/java/feature"
, tags = "@Login"
)
public class TestRunner extends AbstractTestNGCucumberTests {
}
我的 testng.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Android Parallel Execution" parallel="tests" thread-count="2" verbose="7">
<test name="Device1">
<parameter name="platformVersion" value="9.0"/>
<parameter name="emulatorNumber" value="emulator-5554"/>
<parameter name="deviceName" value="Android9_Nexus"/>
<parameter name="port" value="4723"/>
<classes>
<class name="MA.steps.TestRunner"/>
</classes>
</test>
</suite>
我收到以下错误:
java.lang.NullPointerException at screens.myAccountOverviewScreen.logoutAccount(myAccountOverviewScreen.java:104)
它指向以下代码行:
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
这是第一次在我的测试中调用 driver
,但令我困惑的是它甚至没有启动 appium 或启动模拟器就抛出 nullpointerexception
。
问题出在你的测试代码上
您创建了套件 xml 文件以仅包含您的 TestRunner
class。但是整个 appium 实例化逻辑都卡在 Hooks
class 中,它通过 TestNG 配置注释 @BeforeTest
和 @AfterTest
来完成。但是这个 class 既不包含在您的套件中,也不包含您的测试 class (TestRunner
) 扩展它。因此,您的配置不会被调用,从而导致 AppiumDriver
对象的空值。
要解决此问题,您可以执行以下操作之一:
- 编辑您的套件 xml 文件并在其中包含
Hooks
class。 (或) - 构建一个实现
IInvokedMethodListener
的 TestNG 侦听器并将您的驱动程序实例化到其beforeInvocation