自动化预备知识上&&下--Android自动化测试学习历程

时间:2023-03-08 15:52:37

章节:自动化基础篇——自动化预备知识上&&下

主要讲解内容及笔记:

一、需要具备的能力:

测试一年,编程一年,熟悉并掌握业界自动化测试工具(monkey--压力测试、monkeyrunner--基于坐标点的可用作功能测试和回归测试、robotium、UIAutomator-google2013年推出的基于控件的框架),Python脚本写过自动化

二、希望具备能力:

1、linux命令(上学学过,但是忘记了,需要回顾和使用)

2、会android简单开发(只是停留在超级基础阶段,还需要看教程)

3、会eclipse插件开发(需要查看资料,自我学习)

三、业界自动化框架(需要自学)

1、基于坐标点触屏:monkeyrunner、北京播思自研工具

2、基于随机流的单元测试:CTS(针对android的framework的测试,防止把android架构改的面目全非)、Monkey(命令:adb monkey -p -v)

3、基于元素图形对比:SeeTest(网址:http://experitest.com)、I-Test

4、腾讯Bita(bita.qq.com)和GT(gt.tencent.com,关注性能测试)

5、百度云和ITestIn(http://testin.cn)、阿里巴巴(TMTS)

6、基于控件信息:Robotium+Junit4框架、东舟Smart-Robot、美国风河公司:wind test managerment

7、NativeDriver和Selenium(已经被UIAutomator替代)

四、ADB详解

1、ADB——官网文档(PORT:TCP 5037)

ADB(android debug bridge)即调试桥接,是一种命令行工具,可以与你的模拟器或者是andorid设备进行通讯,包括三部分组成:

(1)是一个客户端,可以运行在你的开发机上

(2)是一个服务器,以后台形式运行在你的开发机上,当一个server启动后,它就会绑定TCP的5037端口并且监听从adb客户端发出的请求——所有的adb客户端都使用这个端口5037来与server进行通信,如果安装了其他如腾讯手机助手啊之类的,把这个端口占用了,就会导致adb不可用,就需要通过kill servers将其杀掉

(3)是一个守护进程,使得每一个模拟器或者设备的实例都能够运行在后台

adb.exe的具体位置:安装程序/sdk/platform-tools,如D:\Program Files\adt-bundle-windows-x86-20130717\sdk\platform-tools

2、测试ADB

adb命令行:

(1)adb devices     #查看设备列表

问题:这里提示unauthorized?为什么?

没有授权,也就是说手机连接电脑后提示的USB调试的授权,点击确定后,就能够被识别,不行就多试几次

但是为什么用手机助手就能够装上呢?他怎么处理的未授权的问题呢?

(2)adb install 拖进来的apk文件    #安装apk文件

如:abd install wifinext.apk,之后会提示安装进度和success,即提示成功了

(3)adb uninstall 已经安装的apk文件    #卸载apk文件

adb uninstall wifinext.apk,之后会提示Failure

原因在于安装后的包名已将改变,变为AndroidMainifest.xml文件中<manifest>节点下,package元素所指定的名字

因此使用:adb uninstall com.qihoo.linker ,之后提示success

(4)adb push 拖进来的一个文件  /data/local/tmp     #将某文件push进一个目录下

作用:可以测试当空间被占满之类的情况下程序的运行情况,如可以拖进来一个很大的程序,关注内存等

(5)adb pull          #与push相对,将文件拉出

如:adb pull  /data/local/tmp/xxx.apk    C://

(6)adb kill-server

(7)adb shell之后出现的$:表示没有被root,是#:表示被root

3、AndroidDebugBridge源码详解

ADB的源码位置:D:\Program Files\adt-bundle-windows-x86-20130717\sdk\tools\lib\ddmlib.jar

就是要包含这个ddmlib.jar,具体如何理解:

http://*.com/questions/17381324/how-to-tell-if-android-device-detected-by-adb

这个是在*上的一个问答:关于如何才能知道android设备是否连接通过adb?

查看一下androiddebugbridge的源码,能够看到里面有一个createbrige的方法,源代码如下:

能够搜索到有两个createbridge方法,一种是createbridge()方法,该方法会判断是否存在一个adb连接,是则将其返回;

另一种是createbridge(String osLocation, boolean forceNewBridge)

该方法会生成一个新的adb连接,不论原来是否存在

 /*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.athrun.ddmlib; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.Thread.State;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import org.athrun.ddmlib.Log.LogLevel; /**
* A connection to the host-side android debug bridge (adb)
* <p/>
* This is the central point to communicate with any devices, emulators, or the
* applications running on them.
* <p/>
* <b>{@link #init(boolean)} must be called before anything is done.</b>
*/
public final class AndroidDebugBridge { /*
* Minimum and maximum version of adb supported. This correspond to
* ADB_SERVER_VERSION found in //device/tools/adb/adb.h
*/ private final static int ADB_VERSION_MICRO_MIN = 20;
private final static int ADB_VERSION_MICRO_MAX = -1; private final static Pattern sAdbVersion = Pattern
.compile("^.*(\\d+)\\.(\\d+)\\.(\\d+)$"); //$NON-NLS-1$ private final static String ADB = "adb"; //$NON-NLS-1$
private final static String DDMS = "ddms"; //$NON-NLS-1$
private final static String SERVER_PORT_ENV_VAR = "ANDROID_ADB_SERVER_PORT"; //$NON-NLS-1$ // Where to find the ADB bridge.
final static String ADB_HOST = "127.0.0.1"; //$NON-NLS-1$
final static int ADB_PORT = 5037; private static InetAddress sHostAddr;
private static InetSocketAddress sSocketAddr; private static AndroidDebugBridge sThis;
private static boolean sInitialized = false;
private static boolean sClientSupport; /** Full path to adb. */
private String mAdbOsLocation = null; private boolean mVersionCheck; private boolean mStarted = false; private DeviceMonitor mDeviceMonitor; private final static ArrayList<IDebugBridgeChangeListener> sBridgeListeners = new ArrayList<IDebugBridgeChangeListener>();
private final static ArrayList<IDeviceChangeListener> sDeviceListeners = new ArrayList<IDeviceChangeListener>();
private final static ArrayList<IClientChangeListener> sClientListeners = new ArrayList<IClientChangeListener>(); // lock object for synchronization
private static final Object sLock = sBridgeListeners; /**
* Classes which implement this interface provide a method that deals with
* {@link AndroidDebugBridge} changes.
*/
public interface IDebugBridgeChangeListener {
/**
* Sent when a new {@link AndroidDebugBridge} is connected.
* <p/>
* This is sent from a non UI thread.
*
* @param bridge
* the new {@link AndroidDebugBridge} object.
*/
public void bridgeChanged(AndroidDebugBridge bridge);
} /**
* Classes which implement this interface provide methods that deal with
* {@link IDevice} addition, deletion, and changes.
*/
public interface IDeviceChangeListener {
/**
* Sent when the a device is connected to the {@link AndroidDebugBridge}
* .
* <p/>
* This is sent from a non UI thread.
*
* @param device
* the new device.
*/
public void deviceConnected(IDevice device); /**
* Sent when the a device is connected to the {@link AndroidDebugBridge}
* .
* <p/>
* This is sent from a non UI thread.
*
* @param device
* the new device.
*/
public void deviceDisconnected(IDevice device); /**
* Sent when a device data changed, or when clients are
* started/terminated on the device.
* <p/>
* This is sent from a non UI thread.
*
* @param device
* the device that was updated.
* @param changeMask
* the mask describing what changed. It can contain any of
* the following values: {@link IDevice#CHANGE_BUILD_INFO},
* {@link IDevice#CHANGE_STATE},
* {@link IDevice#CHANGE_CLIENT_LIST}
*/
public void deviceChanged(IDevice device, int changeMask);
} /**
* Classes which implement this interface provide methods that deal with
* {@link Client} changes.
*/
public interface IClientChangeListener {
/**
* Sent when an existing client information changed.
* <p/>
* This is sent from a non UI thread.
*
* @param client
* the updated client.
* @param changeMask
* the bit mask describing the changed properties. It can
* contain any of the following values:
* {@link Client#CHANGE_INFO},
* {@link Client#CHANGE_DEBUGGER_STATUS},
* {@link Client#CHANGE_THREAD_MODE},
* {@link Client#CHANGE_THREAD_DATA},
* {@link Client#CHANGE_HEAP_MODE},
* {@link Client#CHANGE_HEAP_DATA},
* {@link Client#CHANGE_NATIVE_HEAP_DATA}
*/
public void clientChanged(Client client, int changeMask);
} /**
* Initializes the <code>ddm</code> library.
* <p/>
* This must be called once <b>before</b> any call to
* {@link #createBridge(String, boolean)}.
* <p>
* The library can be initialized in 2 ways:
* <ul>
* <li>Mode 1: <var>clientSupport</var> == <code>true</code>.<br>
* The library monitors the devices and the applications running on them. It
* will connect to each application, as a debugger of sort, to be able to
* interact with them through JDWP packets.</li>
* <li>Mode 2: <var>clientSupport</var> == <code>false</code>.<br>
* The library only monitors devices. The applications are left untouched,
* letting other tools built on <code>ddmlib</code> to connect a debugger to
* them.</li>
* </ul>
* <p/>
* <b>Only one tool can run in mode 1 at the same time.</b>
* <p/>
* Note that mode 1 does not prevent debugging of applications running on
* devices. Mode 1 lets debuggers connect to <code>ddmlib</code> which acts
* as a proxy between the debuggers and the applications to debug. See
* {@link Client#getDebuggerListenPort()}.
* <p/>
* The preferences of <code>ddmlib</code> should also be initialized with
* whatever default values were changed from the default values.
* <p/>
* When the application quits, {@link #terminate()} should be called.
*
* @param clientSupport
* Indicates whether the library should enable the monitoring and
* interaction with applications running on the devices.
* @see AndroidDebugBridge#createBridge(String, boolean)
* @see DdmPreferences
*/
public static synchronized void init(boolean clientSupport) {
if (sInitialized) {
throw new IllegalStateException(
"AndroidDebugBridge.init() has already been called.");
}
sInitialized = true;
sClientSupport = clientSupport; // Determine port and instantiate socket address.
initAdbSocketAddr(); MonitorThread monitorThread = MonitorThread.createInstance();
monitorThread.start(); HandleHello.register(monitorThread);
HandleAppName.register(monitorThread);
HandleTest.register(monitorThread);
HandleThread.register(monitorThread);
HandleHeap.register(monitorThread);
HandleWait.register(monitorThread);
HandleProfiling.register(monitorThread);
HandleNativeHeap.register(monitorThread);
} /**
* Terminates the ddm library. This must be called upon application
* termination.
*/
public static synchronized void terminate() {
// kill the monitoring services
if (sThis != null && sThis.mDeviceMonitor != null) {
sThis.mDeviceMonitor.stop();
sThis.mDeviceMonitor = null;
} MonitorThread monitorThread = MonitorThread.getInstance();
if (monitorThread != null) {
monitorThread.quit();
} sInitialized = false;
} /**
* Returns whether the ddmlib is setup to support monitoring and interacting
* with {@link Client}s running on the {@link IDevice}s.
*/
static boolean getClientSupport() {
return sClientSupport;
} /**
* Returns the socket address of the ADB server on the host.
*/
public static InetSocketAddress getSocketAddress() {
return sSocketAddr;
} /**
* Creates a {@link AndroidDebugBridge} that is not linked to any particular
* executable.
* <p/>
* This bridge will expect adb to be running. It will not be able to
* start/stop/restart adb.
* <p/>
* If a bridge has already been started, it is directly returned with no
* changes (similar to calling {@link #getBridge()}).
*
* @return a connected bridge.
*/
public static AndroidDebugBridge createBridge() {
synchronized (sLock) {
if (sThis != null) {
return sThis;
} try {
sThis = new AndroidDebugBridge();
sThis.start();
} catch (InvalidParameterException e) {
sThis = null;
} // because the listeners could remove themselves from the list while
// processing
// their event callback, we make a copy of the list and iterate on
// it instead of
// the main list.
// This mostly happens when the application quits.
IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners
.toArray(new IDebugBridgeChangeListener[sBridgeListeners
.size()]); // notify the listeners of the change
for (IDebugBridgeChangeListener listener : listenersCopy) {
// we attempt to catch any exception so that a bad listener
// doesn't kill our
// thread
try {
listener.bridgeChanged(sThis);
} catch (Exception e) {
Log.e(DDMS, e);
}
} return sThis;
}
} /**
* Creates a new debug bridge from the location of the command line tool.
* <p/>
* Any existing server will be disconnected, unless the location is the same
* and <code>forceNewBridge</code> is set to false.
*
* @param osLocation
* the location of the command line tool 'adb'
* @param forceNewBridge
* force creation of a new bridge even if one with the same
* location already exists.
* @return a connected bridge.
*/
public static AndroidDebugBridge createBridge(String osLocation,
boolean forceNewBridge) {
synchronized (sLock) {
if (sThis != null) {
if (sThis.mAdbOsLocation != null
&& sThis.mAdbOsLocation.equals(osLocation)
&& forceNewBridge == false) {
return sThis;
} else {
// stop the current server
sThis.stop();
}
} try {
sThis = new AndroidDebugBridge(osLocation);
sThis.start();
} catch (InvalidParameterException e) {
sThis = null;
} // because the listeners could remove themselves from the list while
// processing
// their event callback, we make a copy of the list and iterate on
// it instead of
// the main list.
// This mostly happens when the application quits.
IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners
.toArray(new IDebugBridgeChangeListener[sBridgeListeners
.size()]); // notify the listeners of the change
for (IDebugBridgeChangeListener listener : listenersCopy) {
// we attempt to catch any exception so that a bad listener
// doesn't kill our
// thread
try {
listener.bridgeChanged(sThis);
} catch (Exception e) {
Log.e(DDMS, e);
}
} return sThis;
}
} /**
* Returns the current debug bridge. Can be <code>null</code> if none were
* created.
*/
public static AndroidDebugBridge getBridge() {
return sThis;
} /**
* Disconnects the current debug bridge, and destroy the object.
* <p/>
* This also stops the current adb host server.
* <p/>
* A new object will have to be created with
* {@link #createBridge(String, boolean)}.
*/
public static void disconnectBridge() {
synchronized (sLock) {
if (sThis != null) {
sThis.stop();
sThis = null; // because the listeners could remove themselves from the list
// while processing
// their event callback, we make a copy of the list and iterate
// on it instead of
// the main list.
// This mostly happens when the application quits.
IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners
.toArray(new IDebugBridgeChangeListener[sBridgeListeners
.size()]); // notify the listeners.
for (IDebugBridgeChangeListener listener : listenersCopy) {
// we attempt to catch any exception so that a bad listener
// doesn't kill our
// thread
try {
listener.bridgeChanged(sThis);
} catch (Exception e) {
Log.e(DDMS, e);
}
}
}
}
} /**
* Adds the listener to the collection of listeners who will be notified
* when a new {@link AndroidDebugBridge} is connected, by sending it one of
* the messages defined in the {@link IDebugBridgeChangeListener} interface.
*
* @param listener
* The listener which should be notified.
*/
public static void addDebugBridgeChangeListener(
IDebugBridgeChangeListener listener) {
synchronized (sLock) {
if (sBridgeListeners.contains(listener) == false) {
sBridgeListeners.add(listener);
if (sThis != null) {
// we attempt to catch any exception so that a bad listener
// doesn't kill our
// thread
try {
listener.bridgeChanged(sThis);
} catch (Exception e) {
Log.e(DDMS, e);
}
}
}
}
} /**
* Removes the listener from the collection of listeners who will be
* notified when a new {@link AndroidDebugBridge} is started.
*
* @param listener
* The listener which should no longer be notified.
*/
public static void removeDebugBridgeChangeListener(
IDebugBridgeChangeListener listener) {
synchronized (sLock) {
sBridgeListeners.remove(listener);
}
} /**
* Adds the listener to the collection of listeners who will be notified
* when a {@link IDevice} is connected, disconnected, or when its properties
* or its {@link Client} list changed, by sending it one of the messages
* defined in the {@link IDeviceChangeListener} interface.
*
* @param listener
* The listener which should be notified.
*/
public static void addDeviceChangeListener(IDeviceChangeListener listener) {
synchronized (sLock) {
if (sDeviceListeners.contains(listener) == false) {
sDeviceListeners.add(listener);
}
}
} /**
* Removes the listener from the collection of listeners who will be
* notified when a {@link IDevice} is connected, disconnected, or when its
* properties or its {@link Client} list changed.
*
* @param listener
* The listener which should no longer be notified.
*/
public static void removeDeviceChangeListener(IDeviceChangeListener listener) {
synchronized (sLock) {
sDeviceListeners.remove(listener);
}
} /**
* Adds the listener to the collection of listeners who will be notified
* when a {@link Client} property changed, by sending it one of the messages
* defined in the {@link IClientChangeListener} interface.
*
* @param listener
* The listener which should be notified.
*/
public static void addClientChangeListener(IClientChangeListener listener) {
synchronized (sLock) {
if (sClientListeners.contains(listener) == false) {
sClientListeners.add(listener);
}
}
} /**
* Removes the listener from the collection of listeners who will be
* notified when a {@link Client} property changed.
*
* @param listener
* The listener which should no longer be notified.
*/
public static void removeClientChangeListener(IClientChangeListener listener) {
synchronized (sLock) {
sClientListeners.remove(listener);
}
} /**
* Returns the devices.
*
* @see #hasInitialDeviceList()
*/
public IDevice[] getDevices() {
synchronized (sLock) {
if (mDeviceMonitor != null) {
return mDeviceMonitor.getDevices();
}
} return new IDevice[0];
} /**
* Returns whether the bridge has acquired the initial list from adb after
* being created.
* <p/>
* Calling {@link #getDevices()} right after
* {@link #createBridge(String, boolean)} will generally result in an empty
* list. This is due to the internal asynchronous communication mechanism
* with <code>adb</code> that does not guarantee that the {@link IDevice}
* list has been built before the call to {@link #getDevices()}.
* <p/>
* The recommended way to get the list of {@link IDevice} objects is to
* create a {@link IDeviceChangeListener} object.
*/
public boolean hasInitialDeviceList() {
if (mDeviceMonitor != null) {
return mDeviceMonitor.hasInitialDeviceList();
} return false;
} /**
* Sets the client to accept debugger connection on the custom
* "Selected debug port".
*
* @param selectedClient
* the client. Can be null.
*/
public void setSelectedClient(Client selectedClient) {
MonitorThread monitorThread = MonitorThread.getInstance();
if (monitorThread != null) {
monitorThread.setSelectedClient(selectedClient);
}
} /**
* Returns whether the {@link AndroidDebugBridge} object is still connected
* to the adb daemon.
*/
public boolean isConnected() {
MonitorThread monitorThread = MonitorThread.getInstance();
if (mDeviceMonitor != null && monitorThread != null) {
return mDeviceMonitor.isMonitoring()
&& monitorThread.getState() != State.TERMINATED;
}
return false;
} /**
* Returns the number of times the {@link AndroidDebugBridge} object
* attempted to connect to the adb daemon.
*/
public int getConnectionAttemptCount() {
if (mDeviceMonitor != null) {
return mDeviceMonitor.getConnectionAttemptCount();
}
return -1;
} /**
* Returns the number of times the {@link AndroidDebugBridge} object
* attempted to restart the adb daemon.
*/
public int getRestartAttemptCount() {
if (mDeviceMonitor != null) {
return mDeviceMonitor.getRestartAttemptCount();
}
return -1;
} /**
* Creates a new bridge.
*
* @param osLocation
* the location of the command line tool
* @throws InvalidParameterException
*/
private AndroidDebugBridge(String osLocation)
throws InvalidParameterException {
if (osLocation == null || osLocation.length() == 0) {
throw new InvalidParameterException();
}
mAdbOsLocation = osLocation; checkAdbVersion();
} /**
* Creates a new bridge not linked to any particular adb executable.
*/
private AndroidDebugBridge() {
} /**
* Queries adb for its version number and checks it against
* {@link #MIN_VERSION_NUMBER} and {@link #MAX_VERSION_NUMBER}
*/
private void checkAdbVersion() {
// default is bad check
mVersionCheck = false; if (mAdbOsLocation == null) {
return;
} try {
String[] command = new String[2];
command[0] = mAdbOsLocation;
command[1] = "version"; //$NON-NLS-1$
Log.d(DDMS,
String.format("Checking '%1$s version'", mAdbOsLocation)); //$NON-NLS-1$
Process process = Runtime.getRuntime().exec(command); ArrayList<String> errorOutput = new ArrayList<String>();
ArrayList<String> stdOutput = new ArrayList<String>();
int status = grabProcessOutput(process, errorOutput, stdOutput,
true /* waitForReaders */); if (status != 0) {
StringBuilder builder = new StringBuilder(
"'adb version' failed!"); //$NON-NLS-1$
for (String error : errorOutput) {
builder.append('\n');
builder.append(error);
}
Log.logAndDisplay(LogLevel.ERROR, "adb", builder.toString());
} // check both stdout and stderr
boolean versionFound = false;
for (String line : stdOutput) {
versionFound = scanVersionLine(line);
if (versionFound) {
break;
}
}
if (!versionFound) {
for (String line : errorOutput) {
versionFound = scanVersionLine(line);
if (versionFound) {
break;
}
}
} if (!versionFound) {
// if we get here, we failed to parse the output.
Log.logAndDisplay(LogLevel.ERROR, ADB,
"Failed to parse the output of 'adb version'"); //$NON-NLS-1$
} } catch (IOException e) {
Log.logAndDisplay(LogLevel.ERROR, ADB,
"Failed to get the adb version: " + e.getMessage()); //$NON-NLS-1$
} catch (InterruptedException e) {
} finally { }
} /**
* Scans a line resulting from 'adb version' for a potential version number.
* <p/>
* If a version number is found, it checks the version number against what
* is expected by this version of ddms.
* <p/>
* Returns true when a version number has been found so that we can stop
* scanning, whether the version number is in the acceptable range or not.
*
* @param line
* The line to scan.
* @return True if a version number was found (whether it is acceptable or
* not).
*/
@SuppressWarnings("all")
// With Eclipse 3.6, replace by @SuppressWarnings("unused")
private boolean scanVersionLine(String line) {
if (line != null) {
Matcher matcher = sAdbVersion.matcher(line);
if (matcher.matches()) {
int majorVersion = Integer.parseInt(matcher.group(1));
int minorVersion = Integer.parseInt(matcher.group(2));
int microVersion = Integer.parseInt(matcher.group(3)); // check only the micro version for now.
if (microVersion < ADB_VERSION_MICRO_MIN) {
String message = String.format(
"Required minimum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
+ "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
majorVersion, minorVersion, ADB_VERSION_MICRO_MIN,
microVersion);
Log.logAndDisplay(LogLevel.ERROR, ADB, message);
} else if (ADB_VERSION_MICRO_MAX != -1
&& microVersion > ADB_VERSION_MICRO_MAX) {
String message = String.format(
"Required maximum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
+ "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
majorVersion, minorVersion, ADB_VERSION_MICRO_MAX,
microVersion);
Log.logAndDisplay(LogLevel.ERROR, ADB, message);
} else {
mVersionCheck = true;
} return true;
}
}
return false;
} /**
* Starts the debug bridge.
*
* @return true if success.
*/
boolean start() {
if (mAdbOsLocation != null
&& (mVersionCheck == false || startAdb() == false)) {
return false;
} mStarted = true; // now that the bridge is connected, we start the underlying services.
mDeviceMonitor = new DeviceMonitor(this);
mDeviceMonitor.start(); return true;
} /**
* Kills the debug bridge, and the adb host server.
*
* @return true if success
*/
boolean stop() {
// if we haven't started we return false;
if (mStarted == false) {
return false;
} // kill the monitoring services
mDeviceMonitor.stop();
mDeviceMonitor = null; if (stopAdb() == false) {
return false;
} mStarted = false;
return true;
} /**
* Restarts adb, but not the services around it.
*
* @return true if success.
*/
public boolean restart() {
if (mAdbOsLocation == null) {
Log.e(ADB,
"Cannot restart adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
return false;
} if (mVersionCheck == false) {
Log.logAndDisplay(LogLevel.ERROR, ADB,
"Attempting to restart adb, but version check failed!"); //$NON-NLS-1$
return false;
}
synchronized (this) {
stopAdb(); boolean restart = startAdb(); if (restart && mDeviceMonitor == null) {
mDeviceMonitor = new DeviceMonitor(this);
mDeviceMonitor.start();
} return restart;
}
} /**
* Notify the listener of a new {@link IDevice}.
* <p/>
* The notification of the listeners is done in a synchronized block. It is
* important to expect the listeners to potentially access various methods
* of {@link IDevice} as well as {@link #getDevices()} which use internal
* locks.
* <p/>
* For this reason, any call to this method from a method of
* {@link DeviceMonitor}, {@link IDevice} which is also inside a
* synchronized block, should first synchronize on the
* {@link AndroidDebugBridge} lock. Access to this lock is done through
* {@link #getLock()}.
*
* @param device
* the new <code>IDevice</code>.
* @see #getLock()
*/
void deviceConnected(IDevice device) {
// because the listeners could remove themselves from the list while
// processing
// their event callback, we make a copy of the list and iterate on it
// instead of
// the main list.
// This mostly happens when the application quits.
IDeviceChangeListener[] listenersCopy = null;
synchronized (sLock) {
listenersCopy = sDeviceListeners
.toArray(new IDeviceChangeListener[sDeviceListeners.size()]);
} // Notify the listeners
for (IDeviceChangeListener listener : listenersCopy) {
// we attempt to catch any exception so that a bad listener doesn't
// kill our
// thread
try {
listener.deviceConnected(device);
} catch (Exception e) {
Log.e(DDMS, e);
}
}
} /**
* Notify the listener of a disconnected {@link IDevice}.
* <p/>
* The notification of the listeners is done in a synchronized block. It is
* important to expect the listeners to potentially access various methods
* of {@link IDevice} as well as {@link #getDevices()} which use internal
* locks.
* <p/>
* For this reason, any call to this method from a method of
* {@link DeviceMonitor}, {@link IDevice} which is also inside a
* synchronized block, should first synchronize on the
* {@link AndroidDebugBridge} lock. Access to this lock is done through
* {@link #getLock()}.
*
* @param device
* the disconnected <code>IDevice</code>.
* @see #getLock()
*/
void deviceDisconnected(IDevice device) {
// because the listeners could remove themselves from the list while
// processing
// their event callback, we make a copy of the list and iterate on it
// instead of
// the main list.
// This mostly happens when the application quits.
IDeviceChangeListener[] listenersCopy = null;
synchronized (sLock) {
listenersCopy = sDeviceListeners
.toArray(new IDeviceChangeListener[sDeviceListeners.size()]);
} // Notify the listeners
for (IDeviceChangeListener listener : listenersCopy) {
// we attempt to catch any exception so that a bad listener doesn't
// kill our
// thread
try {
listener.deviceDisconnected(device);
} catch (Exception e) {
Log.e(DDMS, e);
}
}
} /**
* Notify the listener of a modified {@link IDevice}.
* <p/>
* The notification of the listeners is done in a synchronized block. It is
* important to expect the listeners to potentially access various methods
* of {@link IDevice} as well as {@link #getDevices()} which use internal
* locks.
* <p/>
* For this reason, any call to this method from a method of
* {@link DeviceMonitor}, {@link IDevice} which is also inside a
* synchronized block, should first synchronize on the
* {@link AndroidDebugBridge} lock. Access to this lock is done through
* {@link #getLock()}.
*
* @param device
* the modified <code>IDevice</code>.
* @see #getLock()
*/
void deviceChanged(IDevice device, int changeMask) {
// because the listeners could remove themselves from the list while
// processing
// their event callback, we make a copy of the list and iterate on it
// instead of
// the main list.
// This mostly happens when the application quits.
IDeviceChangeListener[] listenersCopy = null;
synchronized (sLock) {
listenersCopy = sDeviceListeners
.toArray(new IDeviceChangeListener[sDeviceListeners.size()]);
} // Notify the listeners
for (IDeviceChangeListener listener : listenersCopy) {
// we attempt to catch any exception so that a bad listener doesn't
// kill our
// thread
try {
listener.deviceChanged(device, changeMask);
} catch (Exception e) {
Log.e(DDMS, e);
}
}
} /**
* Notify the listener of a modified {@link Client}.
* <p/>
* The notification of the listeners is done in a synchronized block. It is
* important to expect the listeners to potentially access various methods
* of {@link IDevice} as well as {@link #getDevices()} which use internal
* locks.
* <p/>
* For this reason, any call to this method from a method of
* {@link DeviceMonitor}, {@link IDevice} which is also inside a
* synchronized block, should first synchronize on the
* {@link AndroidDebugBridge} lock. Access to this lock is done through
* {@link #getLock()}.
*
* @param device
* the modified <code>Client</code>.
* @param changeMask
* the mask indicating what changed in the <code>Client</code>
* @see #getLock()
*/
void clientChanged(Client client, int changeMask) {
// because the listeners could remove themselves from the list while
// processing
// their event callback, we make a copy of the list and iterate on it
// instead of
// the main list.
// This mostly happens when the application quits.
IClientChangeListener[] listenersCopy = null;
synchronized (sLock) {
listenersCopy = sClientListeners
.toArray(new IClientChangeListener[sClientListeners.size()]); } // Notify the listeners
for (IClientChangeListener listener : listenersCopy) {
// we attempt to catch any exception so that a bad listener doesn't
// kill our
// thread
try {
listener.clientChanged(client, changeMask);
} catch (Exception e) {
Log.e(DDMS, e);
}
}
} /**
* Returns the {@link DeviceMonitor} object.
*/
DeviceMonitor getDeviceMonitor() {
return mDeviceMonitor;
} /**
* Starts the adb host side server.
*
* @return true if success
*/
synchronized boolean startAdb() {
if (mAdbOsLocation == null) {
Log.e(ADB,
"Cannot start adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
return false;
} Process proc;
int status = -1; try {
String[] command = new String[2];
command[0] = mAdbOsLocation;
command[1] = "start-server"; //$NON-NLS-1$
Log.d(DDMS, String.format(
"Launching '%1$s %2$s' to ensure ADB is running.", //$NON-NLS-1$
mAdbOsLocation, command[1]));
ProcessBuilder processBuilder = new ProcessBuilder(command);
if (DdmPreferences.getUseAdbHost()) {
String adbHostValue = DdmPreferences.getAdbHostValue();
if (adbHostValue != null && adbHostValue.length() > 0) {
// TODO : check that the String is a valid IP address
Map<String, String> env = processBuilder.environment();
env.put("ADBHOST", adbHostValue);
}
}
proc = processBuilder.start(); ArrayList<String> errorOutput = new ArrayList<String>();
ArrayList<String> stdOutput = new ArrayList<String>();
status = grabProcessOutput(proc, errorOutput, stdOutput, false /* waitForReaders */); } catch (IOException ioe) {
Log.d(DDMS, "Unable to run 'adb': " + ioe.getMessage()); //$NON-NLS-1$
// we'll return false;
} catch (InterruptedException ie) {
Log.d(DDMS, "Unable to run 'adb': " + ie.getMessage()); //$NON-NLS-1$
// we'll return false;
} if (status != 0) {
Log.w(DDMS,
"'adb start-server' failed -- run manually if necessary"); //$NON-NLS-1$
return false;
} Log.d(DDMS, "'adb start-server' succeeded"); //$NON-NLS-1$ return true;
} /**
* Stops the adb host side server.
*
* @return true if success
*/
private synchronized boolean stopAdb() {
if (mAdbOsLocation == null) {
Log.e(ADB,
"Cannot stop adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
return false;
} Process proc;
int status = -1; try {
String[] command = new String[2];
command[0] = mAdbOsLocation;
command[1] = "kill-server"; //$NON-NLS-1$
proc = Runtime.getRuntime().exec(command);
status = proc.waitFor();
} catch (IOException ioe) {
// we'll return false;
} catch (InterruptedException ie) {
// we'll return false;
} if (status != 0) {
Log.w(DDMS, "'adb kill-server' failed -- run manually if necessary"); //$NON-NLS-1$
return false;
} Log.d(DDMS, "'adb kill-server' succeeded"); //$NON-NLS-1$
return true;
} /**
* Get the stderr/stdout outputs of a process and return when the process is
* done. Both <b>must</b> be read or the process will block on windows.
*
* @param process
* The process to get the ouput from
* @param errorOutput
* The array to store the stderr output. cannot be null.
* @param stdOutput
* The array to store the stdout output. cannot be null.
* @param displayStdOut
* If true this will display stdout as well
* @param waitforReaders
* if true, this will wait for the reader threads.
* @return the process return code.
* @throws InterruptedException
*/
private int grabProcessOutput(final Process process,
final ArrayList<String> errorOutput,
final ArrayList<String> stdOutput, boolean waitforReaders)
throws InterruptedException {
assert errorOutput != null;
assert stdOutput != null;
// read the lines as they come. if null is returned, it's
// because the process finished
Thread t1 = new Thread("") { //$NON-NLS-1$
@Override
public void run() {
// create a buffer to read the stderr output
InputStreamReader is = new InputStreamReader(
process.getErrorStream());
BufferedReader errReader = new BufferedReader(is); try {
while (true) {
String line = errReader.readLine();
if (line != null) {
Log.e(ADB, line);
errorOutput.add(line);
} else {
break;
}
}
} catch (IOException e) {
// do nothing.
}
}
}; Thread t2 = new Thread("") { //$NON-NLS-1$
@Override
public void run() {
InputStreamReader is = new InputStreamReader(
process.getInputStream());
BufferedReader outReader = new BufferedReader(is); try {
while (true) {
String line = outReader.readLine();
if (line != null) {
Log.d(ADB, line);
stdOutput.add(line);
} else {
break;
}
}
} catch (IOException e) {
// do nothing.
}
}
}; t1.start();
t2.start(); // it looks like on windows process#waitFor() can return
// before the thread have filled the arrays, so we wait for both threads
// and the
// process itself.
if (waitforReaders) {
try {
t1.join();
} catch (InterruptedException e) {
}
try {
t2.join();
} catch (InterruptedException e) {
}
} // get the return code from the process
return process.waitFor();
} /**
* Returns the singleton lock used by this class to protect any access to
* the listener.
* <p/>
* This includes adding/removing listeners, but also notifying listeners of
* new bridges, devices, and clients.
*/
static Object getLock() {
return sLock;
} /**
* Instantiates sSocketAddr with the address of the host's adb process.
*/
private static void initAdbSocketAddr() {
try {
int adb_port = determineAndValidateAdbPort();
sHostAddr = InetAddress.getByName(ADB_HOST);
sSocketAddr = new InetSocketAddress(sHostAddr, adb_port);
} catch (UnknownHostException e) {
// localhost should always be known.
}
} /**
* Determines port where ADB is expected by looking at an env variable.
* <p/>
* The value for the environment variable ANDROID_ADB_SERVER_PORT is
* validated, IllegalArgumentException is thrown on illegal values.
* <p/>
*
* @return The port number where the host's adb should be expected or
* started.
* @throws IllegalArgumentException
* if ANDROID_ADB_SERVER_PORT has a non-numeric value.
*/
private static int determineAndValidateAdbPort() {
String adb_env_var;
int result = ADB_PORT;
try {
adb_env_var = System.getenv(SERVER_PORT_ENV_VAR); if (adb_env_var != null) {
adb_env_var = adb_env_var.trim();
} if (adb_env_var != null && adb_env_var.length() > 0) {
// C tools (adb, emulator) accept hex and octal port numbers, so
// need to accept
// them too.
result = Integer.decode(adb_env_var); if (result <= 0) {
String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
+ ": must be >=0, got " //$NON-NLS-1$
+ System.getenv(SERVER_PORT_ENV_VAR);
throw new IllegalArgumentException(errMsg);
}
}
} catch (NumberFormatException nfEx) {
String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
+ ": illegal value '" //$NON-NLS-1$
+ System.getenv(SERVER_PORT_ENV_VAR) + "'"; //$NON-NLS-1$
throw new IllegalArgumentException(errMsg);
} catch (SecurityException secEx) {
// A security manager has been installed that doesn't allow access
// to env vars.
// So an environment variable might have been set, but we can't
// tell.
// Let's log a warning and continue with ADB's default port.
// The issue is that adb would be started (by the forked process
// having access
// to the env vars) on the desired port, but within this process, we
// can't figure out
// what that port is. However, a security manager not granting
// access to env vars
// but allowing to fork is a rare and interesting configuration, so
// the right
// thing seems to be to continue using the default port, as forking
// is likely to
// fail later on in the scenario of the security manager.
Log.w(DDMS,
"No access to env variables allowed by current security manager. " //$NON-NLS-1$
+ "If you've set ANDROID_ADB_SERVER_PORT: it's being ignored."); //$NON-NLS-1$
}
return result;
} }

在以上源码中,还有一个connect方法和disconnect方法,可以通过复写这两个方法,将adb当前的连接情况打印出来脚本信息

4、ADB在自动化工具和框架中的作用

可以使用adb的方法,通过打印脚本信息来判断设备连接情况,这是最初级且最基础的技术

备注:

BAT测试笔试面试题目:

腾讯笔试题目:

1、如何测试分布式ATM机?     这个针对一些大系统的题目,集群部署

2、使用一个数组实现三个堆栈,要求有效的使用数组的存储空间,可以使用其他数据结构

涉及到一个测试人员对整个系统的了解,包括前段的负载均衡到主备应用等

3、编写一个脚本,统计log文件中首个单词出现的次数:error:xxxx

阿里2面的部分面试题目

1、Robotium源码架构实现

2、Robotium的工具怎么根据id找到脚本id(脚本id和架构映射原理)

3、Monkeyrunner和UIAutomator的原理

4、你们怎么做电量测试(如何做到app进程级别,而不是整机?比如发一个intent请求之类的?)

5、影响手机电量的因素列举一下

6、稳定性和压力怎么做?

7、Robotium WebView怎么实现?

8、怎么让系统不休眠:1、通过PowerManager来精细控制,具体函数请指出    2、在View中设置FLAG_KEEP_SCREE_ON

百度1面题目

1、测试客户端 日文输入法,如果不认识日文,怎么用自动化解决?

2、不用变量交换两个数

3、脚本 怎么用并行和串行调bat批处理

4、怎么解决控件和点触屏自动化(要规划自动化方案)

5、用户安装了百度客户端,怎么实现自动化

6、自动化要验证功能准确性、性能还有UI界面,一个自动化验证多个?还是一个自动化脚本只验证一条用例?

7、怎么实现监控内存   在eclipse显示 DSS是什么意思

8、ANS出现怎么解决?

9、进程和线程 handle和runnable  以及广播和服务

10、Robotium和Monkeyrunner的区别

11、Radiobox和Checkbox自动化脚本怎么复用? (考的是正交法)

12、GC原理

13、android性能自动化怎么做

14、电量对比测试

15、android安全自动化怎么做

16、有个客户装了百度客户端,怎么规划灰度测试版本自动化

17、UI线程阻塞,怎么复现查log

网易云课堂:

上:http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=877113&courseId=712011

下:http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=877114&courseId=712011

金阳光测试

新浪微博:金阳光woody

         

          网站地址

1、百度搜:金阳光测试

2、官网:www.goldensunshine.cc

微信公众号

自动化预备知识上&&下--Android自动化测试学习历程