摘要:使用任务分发系统 Gearman 分布式执行 Calabash 的自动化测试用例,可以达到并行测试手机 APP 的目的。
Gearman 是一个分发任务的程序框架,可以用在各种场合,与 Hadoop 相比,Gearman 更偏向于任务分发功能。它的 任务分布非常简单,简单得可以只需要用脚本即可完成。
Calabash-android 是支持 android 的 UI 自动化测试框架,PC 端使用了 cucumber 框架,通过 http 和 json 与模拟器和真机上安装的测试 apk 通信,测试 apk 调用 robotium 的方法来进行 UI 自动化测试,支持 webview 操作。
calabash 脚本以 使用 calabash 测试开源中国 Android 客户端 为例。
$ sudo apt-get install gearman-job-server
$ gearmand -V
gearmand 1.0.6 - https://bugs.launchpad.net/gearmand
$ sudo apt-get install gearman-tools
$ gearman -H
启动 gearman job server,作为后台服务运行:
$ gearmand -d
启动两个 worker,每个 woker 代表一个手机测试设备 (tester),woker 始终不退出,且没有任何打印:
$ gearman -w -f tester -- ./test-case.sh NEXUS-7 testdata-aa.bashrc
$ gearman -w -f tester -- ./test-case.sh HUAHEI-8860 testdata-bb.bashrc
分发测试用例到各个 worker,收集到所有测试打印后,即完成测试:
./run-suite.sh @BVT
实时查看测试结果,任何一个 worker 测试完一个用例,测试结果会立即打印出来:
tail -f /tmp/test-result
并发测试的效果:
理论上如果顺序执行测试所有用例要 10 个小时,那么只要准备 10 个手机,每个手机对应启动一个 worker:tester,测试时间将缩短到最少 1 个小时。
下面的脚本是在同一台 Ubuntu 电脑上,利用多个 USB 口连接多个手机来并发测试,
如果要在多台电脑上执行并发测试,那要考虑这多台电脑如何获取同一份 apk 和 calabash 脚本,可以考虑从一个公共的 url 去 wget。
从 stdin 接收到的 calabash 测试脚本文件路径,调用 calabash-android 完成测试,再作为 client 调用 printer
#!/bin/bash
if [ x$2 == x ]
then
echo "usage: $0 device-id testdata-xx.bashrc"
echo " device-id get from: adb devices"
exit 1
fi
read line
echo $0 $1 $2
uuid=`uuidgen`
d1=`date +%T`
suite_path=$HOME/git/oschina/android-app/calabash
apk_path=$HOME/git/oschina/android-app/bin/oschina-android-app.apk
echo "test result in /tmp/${uuid}"
echo $d1 at `hostname`:$1 >> /tmp/${uuid}
mkdir -p $HOME/$1
cd $HOME/$1
export ADB_DEVICE_ARG=$1
. $src/$2
calabash-android run $apk_path -r $suite_path/features/ $line 2>&1 | tee -a /tmp/${uuid}
d2=`date +%T`
echo $d2 at `hostname`:$1 >> /tmp/${uuid}
failed=`grep "Failing Scenarios" /tmp/${uuid} | wc -l`
if [ $failed == 0 ]
then
echo "===PASS=== : $line" >> /tmp/${uuid}
else
echo "===FAIL=== : $line" >> /tmp/${uuid}
fi
gearman -f printer < /tmp/${uuid}
rm -f /tmp/${uuid}
从 stdin 接收测试结果,并添加到文件/tmp/test-result
#!/bin/bash
while read line
do
echo "$line" >> /tmp/test-result
done
case_count=`cat /tmp/case_count`
finished=`egrep "===(PASS|FAIL)===" /tmp/test-result | wc -l`
echo -n "Progress:" $finished "/ $case_count [" >> /tmp/test-result
for ((i=0; i<$finished; i++ ))
do
echo -n ">" >> /tmp/test-result
done
let unfinished=$case_count-$finished
for ((i=0; i<$unfinished; i++ ))
do
echo -n "." >> /tmp/test-result
done
echo -en "]\n" >> /tmp/test-result
作为 client,后台一次分发所有 calabash 脚本到 tester,并启动 woker: printer,直到收到所有测试结果打印才退出
#!/bin/bash
if [ x$1 == x ]
then
echo "usage:" $0 "@BVT|@nightly|all|failed"
exit 1
fi
suite_path=$HOME/git/oschina/android-app/calabash
uuid=`uuidgen`
if [ "$1" == "all" ]
then
find $suite_path -name "*.feature" > /tmp/${uuid}
elif [ "$1" == "failed" ]
then
if [ -f /tmp/failed ]
then
cat /tmp/failed > /tmp/${uuid}
else
touch /tmp/${uuid}
fi
elif [[ "$1" == @* ]]
then
grep $1 $suite_path -rl | grep ".feature$" > /tmp/${uuid}
fi
case_count=`cat /tmp/${uuid} | wc -l`
echo $case_count > /tmp/case_count
if [ $case_count == 0 ]
then
echo "NO case to run, exit." | tee /tmp/test-result
rm -f /tmp/${uuid}
exit 1
fi
echo "total $case_count cases." | tee /tmp/test-result
i=0
while read line
do
let i+=1
echo "send No.$i case --- $line"
echo $line | gearman -b -f runcase
done < /tmp/${uuid}
rm -f /tmp/${uuid}
gearman -w -c $case_count -f printer -- ./print-result.sh $case_count
cat /tmp/test-result
grep "===FAIL===" /tmp/test-result | awk '{print $3}' > /tmp/failed
echo "" > /tmp/summary
echo "=================test result summary================" 2>&1 | tee -a /tmp/summary
grep "===PASS===" /tmp/test-result 2>&1 | tee -a /tmp/summary
grep "===FAIL===" /tmp/test-result 2>&1 | tee -a /tmp/summary
fails=`grep "===FAIL===" /tmp/test-result | wc -l`
if [ $fails == 0 ]
then
echo -e "\033[32;1;7mPASS\033[0m :" `grep "===PASS===" /tmp/test-result | wc -l` 2>&1 | tee -a /tmp/summary
else
echo -e "\033[31;1;7mFAIL\033[0m :" `grep "===FAIL===" /tmp/test-result | wc -l` 2>&1 | tee -a /tmp/summary
fi
echo "TOTAL: $case_count" 2>&1 | tee -a /tmp/summary
cat /tmp/summary >> /tmp/test-result