Appium+Cucumber+TestNG how to make iOS real devices parallel Execute

Feature

i want to through TestNG.xml transfer parameters to make cucumber’s running class parallel Execute.i will share the code. Pls help me know what’s wrong.

Code

TestNG.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="suite" parallel="tests" thread-count="2">
    <test name="test1">
        <parameter name="port" value="4777"/>
        <parameter name="udid" value="2600ede04135ffc36df6c6e57cf2b4ad34c52f77"/>
        <parameter name="wdaLocalPort" value="8002"/>
        <classes>
            <class name="rl.app.cucumberTest.runCukesTest1"/>
        </classes>
    </test>
    <test name="test2">
        <parameter name="port" value="4788"/>
        <parameter name="udid" value="9da82887884423f91840e4a4601862d2821de77a"/>
        <parameter name="wdaLocalPort" value="8001"/>
        <classes>
            <class name="rl.app.cucumberTest.runCukesTest2"/>
        </classes>
    </test>
</suite> 

Running Class :runCukesTest1

@CucumberOptions(
        features = {"Feature/app/AFirstFeature/test1.feature"
        },
        glue = {"rl.ipos.stepDefinition"},
        format = {"html:target/cucumber-html-report"},
        plugin = {
                "pretty", "html:target/cucumber-report/runjenkins",
                "json:target/cucumber-report/runjenkins/cucumber.json",
                "rerun:target/cucumber-report/runjenkins/rerun.txt"}
)
public class runCukesTest1 extends AbstractTestNGCucumberTests {
    @Parameters({"port", "udid", "wdaLocalPort"})
    @BeforeTest
    public void setPortUDID(int port, String udid, int wdaLocalPort) {
        Driver.setPort(port);
        Driver.setUdid(udid);
        Driver.setWdaLocalPort(wdaLocalPort);

    }
}

Running Class :runCukesTest2

@CucumberOptions(
        features = {"Feature/app/AFirstFeature/test2.feature"
        },
        glue = {"rl.ipos.stepDefinition"},
        format = {"html:target/cucumber-html-report"},
        plugin = {
                "pretty", "html:target/cucumber-report/runjenkins",
                "json:target/cucumber-report/runjenkins/cucumber.json",
                "rerun:target/cucumber-report/runjenkins/rerun.txt"}
)
public class runCukesTest2 extends AbstractTestNGCucumberTests {
    @Parameters({"port", "udid", "wdaLocalPort"})
    @BeforeTest
    public void setPortUDID(int port, String udid, int wdaLocalPort) {
        Driver.setPort(port);
        Driver.setUdid(udid);
        Driver.setWdaLocalPort(wdaLocalPort);

    }
}

Appium Driver

public class Driver {
    private static int port;
    private static String udid;
    private static int wdaLocalPort;

    protected static IOSDriver<IOSElement> iosDriver;
    protected static AppiumDriverLocalService service;

    private int getWdaLocalPort() {
        System.out.println("\nDriver\nwdaLocalPort:" + wdaLocalPort + "\n");
        return wdaLocalPort;
    }

    public static void setWdaLocalPort(int wdaLocalPort) {
        wdaLocalPort = wdaLocalPort;
    }

    private int getPort() {
        System.out.println("\nDriver\nport:" + port + "\n");
        return port;
    }

    public static void setPort(int port) {
        port = port;
    }

    public static void setUdid(String udid) {
        udid = udid;
    }

    private String getUdid() {
        System.out.println("\nDriver\nudid:" + udid + "\n");
        return udid;
    }

    public static AppiumDriver getDriver() {

        Driver driver = null;

        if (iosDriver == null) {
            AppiumServiceBuilder builder = new AppiumServiceBuilder();
            builder.usingAnyFreePort();
//            builder.usingPort(driver.getPort());
            builder.withIPAddress("127.0.0.1");
            service = AppiumDriverLocalService.buildService(builder);

            service.start();

            if (service == null || !service.isRunning()) {
                throw new AppiumServerHasNotBeenStartedLocallyException("An appium server node is not started!");
            }

            File appDir = new File(System.getProperty("user.dir"), "/apps/");
            File app = new File(appDir, "testApp.app");
            DesiredCapabilities capabilities = new DesiredCapabilities();
            capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
            capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "10.3.0");
            capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "autotest");
            capabilities.setCapability(MobileCapabilityType.UDID, driver.getUdid());
            capabilities.setCapability(IOSMobileCapabilityType.LAUNCH_TIMEOUT, 500000);
            capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.IOS_XCUI_TEST);
            capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
            capabilities.setCapability(MobileCapabilityType.NO_RESET, true);
            capabilities.setCapability("wdaLocalPort", driver.getWdaLocalPort());
            capabilities.setCapability("useNewWDA", true);
            capabilities.setCapability("clearSystemFiles", true);
            iosDriver = new IOSDriver<>(service.getUrl(), capabilities);
            iosDriver.manage().timeouts().implicitlyWait(480, TimeUnit.SECONDS);
            // iosDriver.manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
        }
        return iosDriver;
    }
}

Debug

  1. the Running Class can get the value port,udid, wdaLocalPort.but the Driver class can’t get the values
  2. capabilities.setCapability(MobileCapabilityType.UDID, driver.getUdid());get a message Caused by: java.lang.NullPointerException