Android杂货店-一次自动化测试的记录

是的, 每周一个自定义View的系列第二周就咕咕咕了, 因为我平时使用的工具各种各样, 实在是没有什么办法归为一类来处理, 现在想想, 这里平时实际工作使用的工具反而是更应该分享给大家的, 于是便有了现在新的系列Android杂货店, 多吃才能更好学习不是.

背景

最近一直在做一个蓝牙通信的项目, 由于通信的情况不是很稳定, 就像做一个冒烟测试看一下具体的情况, 不过现场十分的复杂, 需要延时通信, 异步的获取结果, 在根据结果决定相关的操作, 既不是白盒也不是黑盒. 因为是针对开发功能的测试, 纯黑盒的情况下无法获取到一些检测的数据, 而纯白盒的情况下又有许多的功能以及被集成, 只不过没有数据的显示. 加之功能测试流程复杂, 重复性高, 最后通过adb和shell进行了测试

设计与实现

测试的设计来说还是比较简单的, 打开应用-> 检查状态 -> 测试功能1 -> 测试功能2 -> 退出应用 -> 统计信息 -> 下一次循环测试

不过现实起来还是比较麻烦, 既有log日志的信息截取, 还有页面点击的事件触发, 在测试背景也不是需要十分的标准, 需要一个快速测试验证的情况下, 排查了使用辅助功能或者现有的黑白盒测试工具, 采用了adb+shell的方式

简单来说通过adb 来进行输出数据和进行功能控制, 通过shell来进行统计和数据检查和流程控制

工具使用

一般来说, 都是先上代码, 不过这次的情况比较特殊, 需要先介绍许多背景工具的信息, 不然代码对应平时没有这么方面基础的开发者来说可能就难以理解了

adb

adb作为Android开发者来说接显得熟悉的多了, 不过我还是要把使用到的功能进行一个简单的介绍(篇幅有限, 并且很多工具的某个功能详细来说可能就能做一个新的文章了)

adb(Android Debug Bridge), 可以理解为应用开发的一个桥接, 也是用作测试中数据输出和功能控制的的原因

  • adb devices: 用于查看当前电脑连接到的手机设备列表, 当有多台设备的时候就可以通过此指令查看需要控制的设备的标识.
  • adb -s [deviceId]: 用于通过adb控制指定的设备
  • adb logcat -s AUTO_TEST: 用于输出手机中的logcat信息, -s AUTO_TES可以过滤到指定的tag
  • adb shell am: am是Activity Manger的缩写, 可以用于控制手机的Activity, 当前使用了adb shell am force-stop com.clwater.test可以关闭指定的应用, adb -s $deviceID shell am start -n com.clwater.test/clwater.test.StartActivity可以打开指定的应用
  • adb shell input tap [x_posotion] [y_position]: 点击手机的指定位置, 可以在开发者模式中显示坐标的信息来获取坐标的情况, 类似的还可以模拟长按或者是滑动等相关的操作

shell

  • 方法函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #方法的定义,
    function functionName(){
    # echo 输出的内容可以认为是返回值
    # $1 为第一个入参的参数
    # $2 为第二个入参的参数
    echo "$1 $2"
    }
    #方法的使用 其中a和b为入参的参数
    functionName a b
    # 其中需要注意的是, shell为解释型, 如果需要定义变量或方法, 需要在调用前定义好才能调用
  • 获取方法的执行结果, 如果想要知道某些代码的执行结果, 可以通过 `(执行语句)` 或者 **$(执行语句)**来获取
  • 变量的使用 在使用定义好的变量时需要在遍历前添加 **$**来使用
  • sed sed可以理解为针对文件进行处理的工具, 此处 sed -n ‘1p’ $localCountPath 为获取localCountPath路径下文件第一行的信息, 当然sed的功能不只有有这个, sed是拥有许多十分强大的功能
  • awk awk为一个文本分析工具,此处 awk “BEGIN{print $1/$2*100 } 为计算第一个参数/第二个参数*100的结果
  • tail 用于查看文件内容, tail -n 1 $logPath为查看logPath文件的最后一行的内容
  • 输入输出重定向, 一般用于读取或输出内容, 其中 **>>**为将输出以追加的方式重定向到指定文件, **>**为输出重定向到指定文件
  • 字符串截取 **${log##*AUTO_TEST:}**为从左到右输出最后一个AUTO_TEST:字段后的内容
  • if与while, 常见的判断与循环, 这里就不过多的阐述了
  • ==与=, 其中==为相等, =为正则匹配

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#/bin/bash

deviceID="9SV9X20829K00123"

logPath="本地log.log"
localCountPath="统计信息.txt"

# 检查标志位
checkJump=10000

success="success"
fail="fail"

# 从历史文件中获取历史的信息
# 参考shell sed的使用
startCount=`(sed -n '1p' $localCountPath )`
connectCount=`(sed -n '2p' $localCountPath )`
connectSuccess=`(sed -n '3p' $localCountPath )`
genericCount=`(sed -n '4p' $localCountPath )`
genericSuccess=`(sed -n '5p' $localCountPath )`
startOtaCount=`(sed -n '6p' $localCountPath )`
startOtaSuccess=`(sed -n '7p' $localCountPath )`
progressOtaCount=`(sed -n '8p' $localCountPath )`
successProgressOtaCount=`(sed -n '9p' $localCountPath )`


# 获取当前最新的log
function checkLog()
{
# 获取当前目标文件的最新信息
# 参考shell tail的使用
log=`(tail -n 1 $logPath)`
# 分割有用的信息
# 参考sehll 字符串的分割
log=${log##*AUTO_TEST:}

echo $log
}

# 进行相关动作检查
# $1 需要进行检查的动作
# $2 进行检查的时间
function testCheck(){
_index=0
while [ $_index -lt $2 ]
do
let _index=($_index + 1)
# 获取当前最后一行的log
# 参考shell 方法的调用
if [[ `(checkLog)` == $1 ]];
then
_index=$checkJump
echo $success
else
sleep 1
fi
done
if [[ $_index != $checkJump ]]
then
echo $fail
fi
}


# 显示某个流程的统计信息
function showItemCount(){
# $1与$2 参考shell 方法的使用
if [[ $2 != 0 ]];
then
# 计算百分比的情况
# 参考shell awk的使用
f=$(awk "BEGIN{print $1/$2*100 }")%
else
f="0%"
fi

echo "$1/$2($f)"
}

# 保存信息到本地
function saveLoacl(){
# 参考shell > 与>>的使用
echo $startCount > $localCountPath

echo $connectCount >> $localCountPath
echo $connectSuccess >> $localCountPath
echo $genericSuccess >> $localCountPath
echo $genericCount >> $localCountPath
echo $startOtaCount >> $localCountPath
echo $startOtaSuccess >> $localCountPath
echo $progressOtaCount >> $localCountPath
echo $successProgressOtaCount >> $localCountPath
}

# 显示统计信息
function showCount(){

echo "启动: $startCount"
echo "测试流程1: `(showItemCount $connectSuccess $connectCount)`"
echo "测试流程2: `(showItemCount $genericSuccess $genericCount)`"
echo "测试流程3 : `(showItemCount $startOtaSuccess $startOtaCount)`"
echo "测试流程4 : `(showItemCount $successProgressOtaCount $progressOtaCount)`"
saveLoacl

}

# 推出应用
function exitApp(){
echo "关闭应用"
# 参考adb shell am方法 退出指定应用
`(adb -s $deviceID shell am force-stop com.clwater.test)`

showCount
}

# 测试流程4
function checkOTAProgress(){
echo "测试流程4"
let progressOtaCount=($progressOtaCount + 1)

_index=0
# 达到延时120s后进行异常进行处理
# 参考shell while指令
while [ $_index -lt 120 ]
do
let _index=($_index + 1)
log=`(checkLog)`
# 参考shell =~正则匹配
if [[ $log =~ "测试流程4_正则" ]];
then
_index=$checkJump

if [[ $log == "测试流程4_状态1" ]];
then
let successProgressOtaCount=($successProgressOtaCount + 1)
echo "测试流程4_状态1"
sleep 5
exitApp
else
echo "测试流程4_状态2"
exitApp
fi
else
sleep 1
fi
done

if [[ $_index != $checkJump ]]
then
echo "测试流程4_状态超时"
exitApp
fi
}

# 测试流程3
function checkOTA(){
let startOtaCount=($startOtaCount + 1)
echo "测试流程3 预处理1"
sleep 3
echo "测试流程3 预处理2"

# 模拟屏幕点击
# 参考adb shell input 方法
`(adb -s $deviceID shell input tap 658 1130)`

sleep 5
echo "测试流程3 预处理3"
`(adb -s $deviceID shell input tap 530 1960)`
sleep 1
echo "测试流程3中...(20s)"

statu=`(testCheck "测试流程3" 20)`

if [[ $statu == $success ]];
then
let startOtaSuccess=($startOtaSuccess + 1)
echo "测试流程3成功"
checkOTAProgress
else
echo "测试流程3失败"
exitApp
fi

}

# 测试流程2
function checkGeneric(){
let genericCount=($genericCount + 1)
echo "测试流程2...(30s)"
statu=`(testCheck "测试流程2" 30)`

if [[ $statu == $success ]];
then
let genericSuccess=($genericSuccess + 1)
echo "测试流程2成功"
checkOTA
else
echo "测试流程2异常"
exitApp
fi
}

# 测试流程1
function checkConnect(){
let connectCount=($connectCount + 1)
echo "测试流程1检查中...(30s)"
statu=`(testCheck "测试流程1" 30)`

# 参考 shell if 的使用
if [[ $statu == $success ]];
then
let connectSuccess=($connectSuccess + 1)
echo "测试流程1成功"
checkGeneric
else
# 异常流程可以根据异常的情况决定接下来的流程
# 当前为异常情况下推出应用
echo "测试流程2成功"
exitApp
fi
}

# 进行一次的流程操作
function testAPP()
{
echo "启动应用"
sleep 3
# 通过adb 启动应用
# 参考 adb shell am (am为ActivityManager)
# 参考 adb -s 为指定设备
`(adb -s $deviceID shell am start -n com.clwater.test/clwater.test.StartActivity)`

checkConnect

}


function start(){
echo "开始测试"

# while循环 一直执行某个流程的操作
while True
do
echo "========================"
time=$(date "+%Y/%m/%d %H:%M:%S")
# 使得某个数字+1
let startCount=($startCount + 1)
echo "当执行时间: $time"
echo "当执行次数: $startCount"

testAPP

echo ""
done
}

# 开始
start