Search code examples
javanullpointerexceptionappiumdriver

Appium, Java & Testng - find the reason for a NullPointerException


I am getting a NullPointerException before Appium and the emulator launch. So trying to debug by having sysout lines in the code is not helping at all. If anyone has some advice please send through as I am going crazy!

My dependencies:

<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> 

My 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");
    }
}

My 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 {

}

My testng.xml file:

<?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>

And I am receiving the following error:

java.lang.NullPointerException at screens.myAccountOverviewScreen.logoutAccount(myAccountOverviewScreen.java:104)

Which points to the following line of code:

driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);

This ^ is the first time driver is called in my tests, but what baffles me is that it is throwing a nullpointerexception without even launching appium, or starting the emulator.


Solution

  • The problem lies in your test code.

    You created a suite xml file to include only your TestRunner class. But the entire of the appium instantiation logic is stuck in the Hooks class which does it via the TestNG configuration annotation @BeforeTest and @AfterTest. But this class is neither included in your suite, nor your test class (TestRunner) extends it. So your configurations aren't getting invoked leading to a null value for your AppiumDriver object.

    To fix the problem, you can do one of the following:

    1. Edit your suite xml file and include Hooks class also in it. (or)
    2. Build a TestNG listener which implements IInvokedMethodListener and move your driver instantiation into its beforeInvocation