上次简单说了uiautomator的使用,但是无法单独运行。。。测试大量机器的时候无法一个个连接电脑。所以只能想办法用apk来运行shell语句,让test在机子上自动运行。

前置步骤:
1.as上的项目已能在机器上测试通过
2.得到机器的系

统签名(需要获得权限【有不用的方法,试过都不可行只能使用这个了】)

方法主要是建立一个大的项目嵌一个小的model,大项目用来做adb shell的命令行执行(将相应的自动化测试执行),model是测试的内容。

1.新建Android应用
empty Activity,之后next

2.修改其activity_main.xml(添加一个button用来触发命令行执行)

 <Button
        android:onClick="runMyUiautomator"
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="test" />
  1. 修改CMDUtils.java内容如下:

    package cxq.com.mytest;

    import android.util.Log;

    import java.io.BufferedReader; import java.io.InputStreamReader;
    /* 执行命令 */ public class CMDUtils {

    private static final String TAG = "CMDUtils";
    
    public static class CMD_Result {
        public int resultCode;
        public String error;
        public String success;
    
        public CMD_Result(int resultCode, String error, String success) {
            this.resultCode = resultCode;
            this.error = error;
            this.success = success;
        }
    
    }
    
    /**
     * 执行命令
     *
     * @param command         命令
     * @param isShowCommand   是否显示执行的命令
     * @param isNeedResultMsg 是否反馈执行的结果
     * @retrun CMD_Result
     */
    public static CMD_Result runCMD(String command, boolean isShowCommand,
                                    boolean isNeedResultMsg) {
        if (isShowCommand)
            Log.i(TAG, "runCMD:" + command);
        CMD_Result cmdRsult = null;
        int result;
        try {
            Process process = Runtime.getRuntime().exec(command);
            result = process.waitFor();
            if (isNeedResultMsg) {
                StringBuilder successMsg = new StringBuilder();
                StringBuilder errorMsg = new StringBuilder();
                BufferedReader successResult = new BufferedReader(
                        new InputStreamReader(process.getInputStream()));
                BufferedReader errorResult = new BufferedReader(
                        new InputStreamReader(process.getErrorStream()));
                String s;
                while ((s = successResult.readLine()) != null) {
                    successMsg.append(s);
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
                cmdRsult = new CMD_Result(result, errorMsg.toString(),
                        successMsg.toString());
            }
        } catch (Exception e) {
            Log.e(TAG, "run CMD:" + command + " failed");
            e.printStackTrace();
        }
        return cmdRsult;
    }

    }

4.新建一个model,用于写测试脚本
在Android Studio的左侧栏,右击“New – Module – Phone&Table Module”,并填写如下信息
application/library name:MyTestCase
model name:mytestcase

btw.要选add no activity

  1. 修改mytestcase模块的gradle文件

修改默认的runner,在defaultConfig中添加runner

defaultConfig {
        applicationId "个人路径.mytestcase"
        minSdkVersion 23
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

在dependencies中添加依赖

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'junit:junit:4.12'
    compile 'com.android.support.test:runner:0.4.1'
    compile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
}

//用问题其中minSdkVersion等对应的可根据需求更改

6.新建测试用例TestOne类(位置和上篇的项目一样,在src/androidTest内)
只是用来测试的类
代码如下:

import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class TestOne {
    private UiDevice mDevice;

    @Test
    public void demo() throws UiObjectNotFoundException {
        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        mDevice.pressHome();
        mDevice.pressHome();
        UiObject x=mDevice.findObject(new UiSelector().text("图库"));
        x.click();

    }
}

Case说明:

@RunWith注解,代表使用什么runner
@Test注解,表示当前的方法为测试方法,同理还有其他的@Before等注解,具体case的写法本文不赘述 注意!!
如果你有多个test,都只能放在这个类里,不然会有无法找到class的问题

完成到这,记得test(点击方法上的绿开始:run testone)机器能够回到首页显示图库即test可行
(btw之前把apk安装成功到机器,但是修改无效果,卸载重装也不行,但是方法都各自用小绿三角运行了一遍就ok了,可能是刷新了一遍apk)

好,回到上面test过后,会在terminal的框框内有相应的adb shell语句

adb push D:\DEVl\MyTest\mytestcast\build\outputs\apk\mytestcast-debug.apk /data/local/tmp/cxq.com.mytestcast 

在我们点击运行之后,AS会自动将用例打包成apk文件,路径为
$工程目录\build\outputs\apk\工程名-debug.apk

adb install-multiple -r -t /Users/apple/AndroidStudioProjects/MyTest/app/build/outputs/apk/debug/app-debug.apk

安装这个apk到手机

adb shell am instrument -w -r -e debug false -e class cxq.com.mytestcast.TestOne#demo cxq.com.mytestcast.test/android.support.test.runner.AndroidJUnitRunner

使用AndroidJunitRunner启动你的用例

通过分析这个过程,就知道AS是怎么把用例跑起来的,仿照这个原理就可以自己实现通过apk调用uiautomator用例,只要让app中的button的响应事件去执行am instrument命令即可,但是由于执行这个命令也是需要权限的,因此需要给app添加系统签名

  1. 给APP添加系统签名(为大项目)
    大致过程如下:
    7.a. 修改App中的manifest.xml文件,添加android:sharedUserId="android.uid.system"

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:sharedUserId="android.uid.system"
    package="cxq.com.mytest">

7.b. 生成jks文件
build->Generate Signed APK...
新建jks(生成的文件放在大项目下面的文件夹内)
https://img-blog.csdn.net/20160601170943803?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

7.c. 使用keytool-importkeypair对jks文件引入系统签名
把platform.x509.pem、platform.pk8和上一部生成的jks文件统一放到一个文件夹下(我放到了keytool目录下,这样就可以用terminal cd到这个目录下直接授权了)mac不配置环境到目录下执行就可以
此处为命令行代码
./keytool-importkeypair -k [jks文件名] -p [jks的密码] -pk8 platform.pk8 -cert platform.x509.pem -alias [jks的别名]

例如我的对应的就是:

./keytool-importkeypair -k SignDemo.jks -p 123456 -pk8 platform.pk8 -cert platform.x509.pem -alias SignDemo

运行完这条命令之后,我们就得到了有系统签名的jks

需要准备的文件: keytool-importkeypair (下载
platform.x509.pem、platform.pk8(位于../build/target/product/security)
其本质的原理是给apk加上开发者签名(jks文件),使用keytool-importkeypair
对jks文件进行系统签名,在出包的时候,直接使用带有系统签名的jks对apk进行签名,这样编译生成的apk文件就自带系统签名了

btw以上keytool支持macos。

7.d. 配置gradle(app)

在在android区域下(与defaultConfig同级)添加signingConfigs配置:

依次填写jks的路径,密码,别名等

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.cxq.signdemo"
        minSdkVersion 19
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    **signingConfigs {
        release {
            storeFile file("../signApk/SignDemo.jks")
            storePassword '123456'
            keyAlias 'SignDemo'
            keyPassword '123456'
        }
        debug {
            storeFile file("../signApk/SignDemo.jks")
            storePassword '123456'
            keyAlias 'SignDemo'
            keyPassword '123456'
        }
    }**
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
}

8.然后把jks文件放进文件夹,安装到机器就ok
但是老是会有一些问题,注意:

1.myapplication.com.apple.mytest has no signatures that match those in shared user android.uid.system; ignoring!]
这个是没授权成功
2.INSTALL_FAILED_INVALID_APK: /data/app/vmdl1735842778.tmp/11_app-debug signatures are inconsistent
这种记得build->clean project就可以

还有就是记得gradle同步,有错误好好看看具体内容,很多可能是gradle匹配问题之类的

btw.这是借鉴一个大佬的方案,但是遇坑不少,所以可以用来排坑。以下是正文 作者:CrystalChenxiaoqing
原文:https://blog.csdn.net/cxq234843654/article/details/52605441