Appium:测试NG有几个类

时间:2017-09-23 20:14:59

标签: java testng appium

我在执行包含多个类的TestNG文件时遇到问题

我有一个启动appiumserver和webdriver的安装程序类。此方法使用@BeforeTest

进行注释

我使用每个页面具有不同类的pageobject模型以及我的方案的不同类。

我的Scenarioclasses扩展了安装类。

当我执行SetupClass时,第一个类中的方法被执行得很好。但是从第二个类启动方法时失败,因为driver = null。

我可以通过让我的驱动程序保持静态来修复一个设备,但之后我再也无法执行并行测试了。

我也可以使用@BeforeClass作为我的安装方法修复它,但是为每个类启动一个新的webdriver。我不想要这个,因为我想在同一个云设备上执行我的测试。

有人知道如何解决这个问题或任何提示吗?

代码示例

这是我的testng文件:



<?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="Device1">

    <parameter name="device_id" value="ef13de46"/>
    <parameter name="device_name" value="samsung"/>
    <parameter name="platformVersion" value="6.0.1"/>
    <parameter name="platformName" value="Android"/>

    <classes>
        <class name="scenarios.Activation">
            <methods>
                <include name="testActivationFlow"/>
            </methods>
        </class>
        <class name="scenarios.MenuBeforeActivation"/>
    </classes>
    </test>
    <test name="Device2">
        <parameter name="device_id" value="ZX1G423C29"/>
        <parameter name="device_name" value="Nexus"/>
        <parameter name="platformVersion" value="7.0"/>
        <parameter name="platformName" value="Android"/>

        <classes>
            <class name="scenarios.Activation">
                <methods>
                    <include name="testActivationFlow"/>
                </methods>
            </class>
            <class name="scenarios.MenuBeforeActivation"/>
        </classes>
    </test>
</suite>
&#13;
&#13;
&#13;

这是我的设置类:

&#13;
&#13;
package setup;

public class DriverInit
{
    private String appiumServiceUrl;
    public AppiumDriver driver;

    public void startAppium()
    {
        final AppiumDriverLocalService service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder().usingAnyFreePort());
        service.start();
        this.appiumServiceUrl = service.getUrl().toString();
    }

    public void DriverInit(final String device_id, final String device_name, final String platformVersion, final String platformName) throws Exception
    {

        final DesiredCapabilities capabilities = new DesiredCapabilities();

        capabilities.setCapability("app", System.getProperty("user.dir") + "/src/test/resources/app/" + "App.apk");

        capabilities.setCapability("deviceName", device_name);
        capabilities.setCapability("udid", device_id);
        capabilities.setCapability("platformName", platformName);
        capabilities.setCapability("platformVersion", platformVersion);
       capabilities.setCapability("appPackage", "<packagename>");
        capabilities.setCapability("appActivity", "<Appactivity>");
        capabilities.setCapability("autoGrantPermissions", true);
        //capabilities.setCapability("autoAcceptAlerts", true);
        capabilities.setCapability("noReset", true);
        capabilities.setCapability("fullReset", false);

        this.driver = new AndroidDriver(new URL(this.appiumServiceUrl), capabilities);
    }

    @Test
    @BeforeTest(alwaysRun = true)
    @Parameters({"device_id", "device_name", "platformVersion", "platformName"})
    public AppiumDriver setDriver(final String device_id, final String device_name, final String platformVersion, final String platformName) throws Exception
    {
        startAppium();
        DriverInit(device_id, device_name, platformVersion, platformName);
        this.driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        return this.driver;
    }

    public AppiumDriver getDriver()
    {
        return this.driver;
    }

    public void tearDown() throws Exception
    {
        this.driver.quit();
    }


}
&#13;
&#13;
&#13;

我还有一个带有一些基本动作的基础类

&#13;
&#13;
public class Basis
{
    public AppiumDriver driver;

    public Basis(final AppiumDriver driver)
    {
        this.driver = driver;
    }
  ...
  
  }
&#13;
&#13;
&#13;

我在页面对象模型之后有一些页面类

&#13;
&#13;
public class NamePage extends Basis
{
    public NamePage(final AppiumDriver driver)
    {
        super(driver);
    }


    By nameField = By.id("edittext_name");
    By checkBox = By.id("checkbox_wallet_tac");
    By text = By.id("textview_wallet_tac");
    By buttonNext = By.id("button_next");
    By buttonCancel = By.id("button_cancel");


    public void enterName(final String strName)
    {
        this.driver.findElement(this.nameField).sendKeys(strName);
        this.driver.hideKeyboard();
    }

    public void acceptTerms()
    {
        this.driver.findElement(this.checkBox).click();
    }

    public void confirmName()
    {
        this.driver.findElement(this.buttonNext).click();
    }

}
&#13;
&#13;
&#13;

我有测试课程

&#13;
&#13;
public class Activation extends DriverInit
{

    @Test
    public void testActivationFlow() throws Exception
    {
        this.driver.resetApp();

        new Basis(this.driver).swipeLeft();

        new Basis(this.driver).swipeLeft();

        new Basis(this.driver).swipeLeft();

        new Basis(this.driver).swipeLeft();

        new WelcomePage(this.driver).startActivation();

        new NamePage(this.driver).enterName("Tester");

        new NamePage(this.driver).acceptTerms();

        new NamePage(this.driver).confirmName();

        new PinCodePage(this.driver).setPinCode();

        new PinHelper(this.driver).setPin();

        Thread.sleep(10000);

    }
}

public class MenuBeforeActivation extends DriverInit
{

    @Test
    public void testWhereCanIPay()
    {
        new MainMenuPage(this.driver).openMenu();

        new MainMenuPage(this.driver).openWherePay();

        //TODO Add assertions Webpage is opened (Title + Content)
    }

    @Test
    public void testInfoMenu()
    {
        new MainMenuPage(this.driver).openMenu();

        new MainMenuPage(this.driver).openInfo();

        new InfoPage(this.driver).openFAQ();

        //TODO Add assertions FAQ Webpage is opened

        new Basis(this.driver).back();

        new InfoPage(this.driver).openPrivacy();

        // Add assertions Privacy Text is shown

        new Basis(this.driver).back();

     

     
    }
    }
&#13;
&#13;
&#13;

Error log : 
java.lang.NullPointerException
    at pages.menuPages.MainMenuPage.openMenu(MainMenuPage.java:31)
    at scenarios.MenuBeforeActivation.testWhereCanIPay(MenuBeforeActivation.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:645)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
    at org.testng.TestRunner.privateRun(TestRunner.java:756)
    at org.testng.TestRunner.run(TestRunner.java:610)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:387)
    at org.testng.SuiteRunner.access$000(SuiteRunner.java:39)
    at org.testng.SuiteRunner$SuiteWorker.run(SuiteRunner.java:421)
    at org.testng.internal.thread.ThreadUtil$2.call(ThreadUtil.java:64)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

3 个答案:

答案 0 :(得分:0)

在开始第二堂课之前 - 检查司机是否可用。 - 检查第一个类是否正在调用tearDown()方法并进行清理。 驱动程序。 - 如果第二类独立于第一类,则在setup()方法之前初始化驱动程序。

要并行执行: - 设置xml文件以传递参数 - 从CLI传递参数。

答案 1 :(得分:0)

以下是使用TestNG解决此问题的方法

将初始化逻辑移动为

的一部分
  • org.testng.ITestListener - 如果您希望每<test>个代码只执行一次设置(即,而不是使用@BeforeTest
  • org.testng.ISuiteListener - 如果您希望每<suite>个代码只执行一次设置(即,而不是使用@BeforeSuite
  • 使用setAttribute()方法将初始化数据保留为ITestContext(此代表<test>代码)或ISuite的属性(此代表<suite> 1}}标签)。
  • 通过以下方式将此监听器连接到TestNG:
    • <listeners>代码(或)
    • @Listeners注释(或)
    • 服务加载器。

您可以在我的this博文中看到一些示例。

您可以从我的this博客中了解有关侦听器和布线的更多信息。

答案 2 :(得分:0)

尝试将@BeforeSuite用于DriverInit,这样它将在所有测试之前启动一次