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

主要讲解内容及笔记:

一、需要具备的能力:

测试一年,编程一年,熟悉并掌握业界自动化测试工具(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://stackoverflow.com/questions/17381324/how-to-tell-if-android-device-detected-by-adb

这个是在stackoverflow上的一个问答:关于如何才能知道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自动化测试学习历程的更多相关文章

  1. app电池续航上&&下--Android自动化测试学习历程

    章节:自动化基础篇——电池续航自动化测试上&&下 主要讲解内容及笔记: 一.影响手机电量的因素和理论: 下面是一个表格:当今主流手机显示屏技术.机型与功耗对照表:   技术  类型   ...

  2. MonkeyRunner原理初步--Android自动化测试学习历程

    章节:自动化基础篇——MonkeyRunner原理初步 主要讲解内容及笔记: 一.理论知识和脚本演示 最佳方式是上官网文档去查看monkeyrunner的介绍,官网上不去,就找了一个本地的androi ...

  3. Robotium原理初步--Android自动化测试学习历程

    章节:自动化基础篇——Robotium原理初步(第四讲) 主要讲解内容与笔记: 一.基于控件 1.spinner——下拉菜单 2.TabHost——左右滑动选择菜单,类似电话本 3.Gallery—— ...

  4. 百度Cafe原理--Android自动化测试学习历程

    主要讲解内容及笔记: 一.Cafe原理 Cafe是一款自动化测试框架,解决问题:跨进程测试.快速深度测试 官网:http://baiduqa.github.io/Cafe/ Cafe provides ...

  5. Android-Junit-Report测试报告生成——Android自动化测试学习历程

    视频地址: http://www.chuanke.com/v1983382-135467-384869.html 这个内容其实已经在用了,我在上一篇文章robotium—只有apk文件的测试中已经讲过 ...

  6. Appium原理初步--Android自动化测试学习历程

    章节:自动化基础篇——Appium原理初步(第七讲) 本期关键词: Appium.跨语言跨平台.Bootstrap 主要讲解内容及笔记: 一.what is appium 一种封装了uiautomat ...

  7. Selenium原理初步--Android自动化测试学习历程

    章节:自动化基础篇——Selenium原理初步(第五讲) 注:其实所有的东西都是应该先去用,但是工具基本都一样,底层都是用的最基础的内容实现的,测试应该做的是: (1)熟练使用工具,了解各个工具的利弊 ...

  8. Monkey原理初步和改良优化--Android自动化测试学习历程

    章节:自动化基础篇——Monkey原理初步和改良优化(第三讲) 主要讲解内容与笔记: 一.理论知识: 直接看文档,来了解monkey的概念.基本原理,以及如何使用. First,what is And ...

  9. Instrumentation类——Android自动化测试学习历程

    这里需要把Instrumentation类的视频的上.中.下三集一起看,把内容总结一下... 视频地址: http://study.163.com/course/courseLearn.htm?cou ...

随机推荐

  1. 廖雪峰Java1-2Java程序基础-2变量和数据类型

    1.变量 变量是可以持有某个基本类型的数值,或者指向某个对象. 变量必须先定义后使用 定义: 变量类型 变量名 = 初始值; 2.java基本数据类型 整数类型:long int short byte ...

  2. java study文件读写

    文件读写 如果在代码中写入大量的数据,会增加代码的冗余度,通过读取文件的方式,可以精简代码,便于数据的修改和代码的维护 IO流的分类:字节流和字符流 字符流 字符输出流:写文本文件的,抽象基类java ...

  3. 邮件服务器fixpost服务(1)

    发邮件所用的协议,SMTP协议,端口TCP25 收邮件所用的协议,pop3.imap协议 邮件客户端(MUA):foxmail.闪电邮.邮件大师.outlook 搭建邮件服务器所用到的软件(MTA邮件 ...

  4. js 获取上传文件的字节数及内容

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. 折腾了好久,thinkphp5打开提示加载failed to open stream: No such file or directory in think start.php

    GIT上下载的THINKPHP5记得先 composer update 我就是没update ,折腾了1个小时,才想起来这个事 thinkphp5默认首页打开空白 打开报错提示  提示thinkphp ...

  6. Git 代码版本还原方法

    因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,Git 代码版本还原方法 在使用 Git 管理自己的代码和资料时,难免会遇到意料 ...

  7. WPF 自定义属性

    做了一个自定义控件和一个自定义Grid,里面的元素可以随着绑定属性变化: 效果图(一定滑块): 关键代码: 1.自定义属性代码: public class MyGrid : Grid { public ...

  8. 下载bilibili视频

    http://www.urlgot.com/zh_CN/

  9. MFC-Dialog各函数的执行顺序

    CDlgTestDlg::CDlgTestDlg CDlgTestDlg::DoModal CDialog::DoModal CDlgTestDlg::PreSubclassWindow CDlgTe ...

  10. 14 ConfigParse模块

    1.ConfigParse模块的基本概念 此模块用于生成和修改常见配置文档. ConfigParser 是用来读取配置文件的包. 配置文件的格式如下:中括号“[ ]”内包含的为section.sect ...