Appium appium+testNG 自动化测试

小怪 · 2017年09月01日 · 最后由 小怪 回复于 2017年09月25日 · 1500 次阅读

在做公司 app 自动化测试,在做到 testNG 套件测试的时候,就会报错,详情是:

java.lang.AssertionError: expected object to not be null
    at org.testng.Assert.fail(Assert.java:94)
    at org.testng.Assert.assertNotNull(Assert.java:404)
    at org.testng.Assert.assertNotNull(Assert.java:389)
    at com.yiibai.primera.testng.cases.HomeTest.initDriver(HomeTest.java:31)
    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:497)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
    at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
    at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:175)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:107)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
    at org.testng.TestNG.run(TestNG.java:1057)
    at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:132)
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:230)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:76)

部分代码截图:(初始化 dirver 类)

package com.yiibai.primera.testng.base;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.http.util.TextUtils;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Listeners;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;

/**
 * 测试用例的父类 
 */
public class InitAppium {
    /*公共参数区*/
    public static String device = "Android";
    // 调试设备名字
    public static String deviceName = "fd47af2d7d42";
    public static String udid = deviceName;
    // public static String deviceName = "X8QDU14A18000077";
    // 调试设备系统版本
    public static String platformVersion = "4.1";
    //dirver的session的超时时间,默认是60秒
    public static String commandTimeout = "6000";
    //automationName表示appium使用的测试引擎,默认是appium,也可以是uiautomator
    public static String automationName = "appium";
    // 不重置应用数据,如重新启动登录过的App时,仍然是登录状态,不需要重新登录
    public static String noReset = "True";

    /*android特有的配置*/
    // 是否不重新签名
    public static String noSign = "True";
    // unicodeKeyboard设置为true表示我们要使用appium自带的输入法,用来支持中文和隐藏键盘,并且将其设置为默认输入法
    public static String unicodeKeyboard = "True";
    // 在执行完测试之后,将手机的输入法从appium输入法还原成手机默认输入法
    public static String resetKeyboard = "True";
    //_当你的其实activity和真正启动后的activity不一致的时候,请把启动的activity放在这里
    public static String waitActivity = "";


    // app路径
    public static String appPath = System.getProperty("user.dir") 
            + "/src/main/java/apps/PN_ADS.apk";
    // 包名
    public static String appPackage = "com.turbo.turbo.mexico";
    // 要启动的Activity
//   public static String appActivity =".baiyi.jj.app.activity.LogoActivity";
    public static String appActivity = "";

    public AndroidDriver<AndroidElement> driver;

    // 构造方法
    public InitAppium() {
        this(new Builder());
    }

    public InitAppium(Builder builder) {

        device = builder.device;
        deviceName = builder.deviceName;
        udid = builder.udid;
        commandTimeout = builder.commandTimeout;
        automationName = builder.automationName;
        platformVersion = builder.platformVersion;
        noReset = builder.noReset;

        noSign = builder.noSign;
        unicodeKeyboard = builder.unicodeKeyboard;
        resetKeyboard = builder.resetKeyboard;

        appActivity = builder.appActivity;
        appPackage = builder.appPackage;
        appPath = builder.appPath;
    }

    /**
     * appium启动参数
     *
     * @throws MalformedURLException
     * @throws InterruptedException 
     */
    @BeforeSuite
    public void beforeSuite() throws MalformedURLException, InterruptedException {
        System.out.println("beforeSuite begin---");
        //启动appium服务
//      AppiumDriverLocalService service = AppiumDriverLocalService.buildDefaultService();
//      service.start();

        DesiredCapabilities capabilities = new DesiredCapabilities();
        //共用参数区
        capabilities.setCapability("device", device);
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, deviceName);
        capabilities.setCapability(MobileCapabilityType.UDID, udid);
        capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
        capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, commandTimeout);
        capabilities.setCapability(MobileCapabilityType.NO_RESET, noReset);
        capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, automationName);
        // 支持中文
        capabilities.setCapability(AndroidMobileCapabilityType.UNICODE_KEYBOARD, unicodeKeyboard);
        capabilities.setCapability(AndroidMobileCapabilityType.RESET_KEYBOARD,resetKeyboard);
        capabilities.setCapability(AndroidMobileCapabilityType.NO_SIGN, noSign);
//      capabilities.setCapability(AndroidMobileCapabilityType.APP_WAIT_ACTIVITY, waitActivity);


        capabilities.setCapability("app", new File(appPath).getAbsolutePath());
        capabilities.setCapability("appPackage", appPackage);
        // 打开的activity
        if (!TextUtils.isEmpty(appActivity)) {
            capabilities.setCapability("appActivity", appActivity);
        }
        // System.out.println("appActivity is: " +
        // capabilities.getCapability(appActivity));
        // 启动Driver
        driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"),
                capabilities);
        System.out.println("driver is:" + driver);
        System.out.println("beforeSuite over----");
    }

    @AfterSuite
    public void afterTest() {
        driver.quit();
    }

//  @AfterClass
//  public void afterClass() {
//      // 每一个用例完毕结束这次测试
//       driver.quit();
//  }
    /**
     * 打印字符 未引用
     * 
     * @param str
     *            要打印的字符
     */
    public <T> void print(T str) {
        if (!TextUtils.isEmpty(String.valueOf(str))) {
            System.out.println(str);
        } else {
            System.out.println("输出了空字符");
        }
    }

}

测试类:

public class HomeTest extends InitAppium {

    private HomeOperate homeOperate;

    @BeforeClass
    public void initDriver() throws MalformedURLException{
        System.out.println("@beforeClass driver is:");
        System.out.println(driver);
        Assert.assertNotNull(driver);                                    此处报错driver为空
        homeOperate = new HomeOperate(driver);
    }

    /**
     * 首页刷新验证
     */
    @Test(enabled = false)
    public void refresh(){
        boolean flag = homeOperate.refresh();
        Assertion.verifyEquals(flag,false,"首页刷新验证");
        print("首页刷新验证:"+ flag);
    }

testNG.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite"> <!--parallel="true" 并行 -->
    <test name="testAll">
        <classes>
            <class name="com.yiibai.primera.testng.cases.HomeTest" />
            <!-- <class name="com.yiibai.primera.testng.cases.RegisterTest" />
            <class name="com.yiibai.primera.testng.cases.LoginTest" />
            <class name="com.yiibai.primera.testng.cases.PersonalCenterTest" />
            <class name="com.yiibai.primera.testng.cases.NewsDetailsTest" /> -->
        </classes>
        <listeners>
            <listener class-name="org.uncommons.reportng.HTMLReporter" />
            <listener class-name="org.uncommons.reportng.JUnitXMLReporter" />
        </listeners>
    </test><!--Test -->
</suite><!--Suite -->

说明 testNG.xml classes 节点里面,如果只保留一条 class 时是通过的 但是有过多余一条就会报错,初始化 driver 的过程都正常,也初始化成功的,就是在断言 driver 是否为空时报错,driver 为空,求懂的大神帮助下

共收到 2 条回复 时间 点赞

因为你所有的子类都继承了 initAppium 这个父类,子类 HomeTest 持有的 driver 和子类 LoginTest 持有的 driver 内存地址是不一样的,但是又因为 TestNG 有 beforesuite 的限制存在,所以你的 driver 只被初始化一次。你如果把 driver 的初始化放到@beforeclass下应该就行了。

谢谢@lewis,就是你所提到的呢,现在已经正常了,万分感谢!!!

小怪 关闭了讨论 09月25日 11:57
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册