该文为 macaca 的 nodejs 版本 样例https://github.com/macacajs/macaca-test-sample
macaca java 版本 https://github.com/macacajs/wd.java
macaca python 版本 https://github.com/macacajs/wd.py
类似于上一篇的思路。
https://testerhome.com/topics/5634
D:\macaca\me-app
拷贝 D:\macaca\macaca-test-sample-master 官方示例脚本下的依赖文件 app 、package.json、 README.md
到新项目 me-app 下。为图方便。macaca-test 文件夹也整个 copy 过来。
您还需要将您的 apk 拷贝到目录\me-app\app 下。
D:\macaca\me-app\macaca-test
将示例脚本 macaca-mobile-sample.test.js 重命名为 android-acp-sample.test.js
开始编辑修改 android-acp-sample.test.js 脚本的内容。
我们用到的是 macaca 团队刚发布的 app-inspector,关于该工具的安装部署请参考https://testerhome.com/topics/5626
只是简单的测试下,看是否可以如此构建自己的用例项目。所以业务流程只是简单的找到登录页 输入用户名 输入密码 点击登录而已 注释掉删除掉了一些验证步骤和自己不了解的原脚本内容。
其中截图实际是有问题的,因为环境目录设置问题。一会儿抽空看下调一下。
'use strict';
var path = require('path');
var _ = require('macaca-utils');
var platform = process.env.platform || 'Android';
platform = platform.toLowerCase();
var iOSOpts = {
platformVersion: '9.3',
deviceName: 'iPhone 5s',
platformName: 'iOS',
//bundleId: 'xudafeng.ios-app-bootstrap',
app: path.join(__dirname, '..', 'app', `${platform}-app-bootstrap.zip`)
};
var androidOpts = {
platformName: 'Android',
//package: 'com.github.android_app_bootstrap',
//activity: 'com.github.android_app_bootstrap.activity.WelcomeActivity',
app: path.join(__dirname, '..', 'app', `your android apk.apk`)
};
var wd = require('webdriver-client')(_.merge({}, platform === 'ios' ? iOSOpts : androidOpts));
// override back for ios
wd.addPromiseChainMethod('customback', function() {
if (platform === 'ios') {
return this;
}
return this
.back();
});
describe('macaca mobile sample', function() {
this.timeout(5 * 60 * 1000);
var driver = wd.initPromiseChain();
driver.configureHttp({
timeout: 600000
});
before(function() {
return driver
.initDriver();
});
after(function() {
return driver
.sleep(1000)
.quit();
});
it('#1 Access 我的', function() {
return driver
.elementById('com.acp.aicaitencent:id/tvBottomTab4')
.click()
.sleep(1000);
});
it('#2 should display 我的page', function() {
return driver
.takeScreenshot();
});
it('#3 Access 立即登录/注册', function() {
return driver
.elementById('com.acp.aicaitencent:id/layoutLogin')
.click()
.sleep(1000);
});
it('#4 should display 登录Page', function() {
return driver
.takeScreenshot();
});
it('#5 Edit and Login', function() {
return driver
.elementById('com.acp.aicaitencent:id/etUserName')
.sendKeys('***********')
.sleep(5000)
.elementById('com.acp.aicaitencent:id/etPwd')
.sendKeys('***********')
.sleep(5000)
.elementById('com.acp.aicaitencent:id/tvLogin')
.click()
.sleep(5000)
.takeScreenshot();
});
});
PS:2016年8月12日补充
书接上文,今天早上来又看了一遍原作者的 macaca-mobile-sample.test.js 样例,原作者为了更好的演示,大家看
it('#7 should works with web', function() {
return driver
.webview()
.elementById('index-kw')
.sendKeys('中文+TesterHome')
.elementById('index-bn')
.tap()
.sleep(5000)
.source()
.then(function(html) {
html.should.containEql('TesterHome');
})
.takeScreenshot();
});
it('#8 should logout success', function() {
return driver
.native()
.elementByName('PERSONAL')
.click()
.sleep(1000)
.takeScreenshot()
.elementByName('Logout')
.click()
.sleep(1000)
.takeScreenshot();
.webview() .native() 大家明白了吧 这就是展示 webview 元素定位 和 native 原生元素定位。 所以大家还是多研究样例 先把简单的搞懂模仿起来,再进行复杂的,一步一步来。
老样子,你需要到有 package.json 文件的 D:\macaca\me-app 目录下执行下 npm i 来为 me-app 准备 macaca 的组件包依赖。
成功看到安装成功日志后,接下来便可以执行用例脚本了。
先启动个安卓模拟器,此处我依然启动的是 Genymotion 模拟器。adb devices -l 查看下是否启动正常。
cd 到 macaca-test 目录下
D:\macaca\me-app\macaca-test>macaca run -d android-acp-sample.test.js --verbose
>> index.js:17:12 [master] pid:10376 webdriver server start with config:
{ port: 3456,
window: true,
ip: '*.*.*.*',
host: 'cmd-PC',
loaded_time: '2016-08-09 10:30:03' }
>> middlewares.js:17:10 [master] pid:10376 base middlewares attached
>> router.js:108:10 [master] pid:10376 router set
>> webdriver sdk launched
>>
>>
macaca mobile sample
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session, jsonBody: {"desiredCapabilities":{"autoAcceptAlerts":true,"platformName":"Android","app":"D:\\macaca\\me-app\\app\\your android apk.apk","browserName":"firefox","version":"","javascriptEnabled":true,"platform":"ANY"}}
>> session.js:47:10 [master] pid:10376 Creating session, sessionId: b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0.
>> helper.js:191:12 [master] pid:10376 Using local app form D:\macaca\me-app\app\your android apk.apk
INSTRUMENTATION_STATUS: numtests=1
INSTRUMENTATION_STATUS: stream=
com.android.uiautomator.client.Initialize:
INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner
INSTRUMENTATION_STATUS: test=testStartServer
INSTRUMENTATION_STATUS: class=com.android.uiautomator.client.Initialize
INSTRUMENTATION_STATUS: current=1
>> socket server ready
>> socket client ready
recive: {"cmd":"wake","args":{}}
return: {"success":true,"data":true}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"{\"autoAcceptAlerts\":true,\"platformName\":\"Android\",\"app\":\"D:\\\\macaca\\\\me-app\\\\app\\\\your android apk.apk\",\"browserName\":\"firefox\",\"version\":\"\",\"javascriptEnabled\":true,\"platform\":\"ANY\",\"window\":true}"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element, jsonBody: {"using":"id","value":"com.acp.aicaitencent:id/tvBottomTab4"}
recive: {"cmd":"find","args":{"strategy":"id","selector":"com.acp.aicaitencent:id/tvBottomTab4","multiple":false}}
return: {"success":true,"data":{"ELEMENT":"1"}}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"{\"ELEMENT\":\"1\"}"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element/1/click, jsonBody: {}
recive: {"cmd":"click","args":{"elementId":"1"}}
return: {"success":true,"data":true}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"true"}
>>
>> √ #1 Access 我的 (1269ms)
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: GET url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/screenshot, jsonBody: {}
>> responseHandler.js:50:12 [master] pid:10376 Send Error Respone to Client: Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-150nd76.png"
>> responseHandler.js:56:14 [master] pid:10376 Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-150nd76.png"
at ChildProcess.exithandler (child_process.js:213:12)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at maybeClose (internal/child_process.js:827:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-150nd76.png"
at ChildProcess.exithandler (child_process.js:213:12)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at maybeClose (internal/child_process.js:827:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
>>
>> 1) #2 should display 我的page
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element, jsonBody: {"using":"id","value":"com.acp.aicaitencent:id/layoutLogin"}
recive: {"cmd":"find","args":{"strategy":"id","selector":"com.acp.aicaitencent:id/layoutLogin","multiple":false}}
return: {"success":true,"data":{"ELEMENT":"2"}}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"{\"ELEMENT\":\"2\"}"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element/2/click, jsonBody: {}
recive: {"cmd":"click","args":{"elementId":"2"}}
return: {"success":true,"data":true}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"true"}
>>
>> √ #3 Access 立即登录/注册 (1441ms)
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: GET url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/screenshot, jsonBody: {}
>> responseHandler.js:50:12 [master] pid:10376 Send Error Respone to Client: Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-14ljgkf.png"
>> responseHandler.js:56:14 [master] pid:10376 Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-14ljgkf.png"
at ChildProcess.exithandler (child_process.js:213:12)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at maybeClose (internal/child_process.js:827:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-14ljgkf.png"
at ChildProcess.exithandler (child_process.js:213:12)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at maybeClose (internal/child_process.js:827:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
2) #4 should display 登录Page
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element, jsonBody: {"using":"id","value":"com.acp.aicaitencent:id/etUserName"}
recive: {"cmd":"find","args":{"strategy":"id","selector":"com.acp.aicaitencent:id/etUserName","multiple":false}}
return: {"success":true,"data":{"ELEMENT":"3"}}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"{\"ELEMENT\":\"3\"}"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element/3/value, jsonBody: {"value":["*****"]}
recive: {"cmd":"setText","args":{"elementId":"3","text":"******"}}
return: {"success":true,"data":true}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"true"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element, jsonBody: {"using":"id","value":"com.acp.aicaitencent:id/etPwd"}
recive: {"cmd":"find","args":{"strategy":"id","selector":"com.acp.aicaitencent:id/etPwd","multiple":false}}
return: {"success":true,"data":{"ELEMENT":"4"}}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"{\"ELEMENT\":\"4\"}"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element/4/value, jsonBody: {"value":["*****"]}
recive: {"cmd":"setText","args":{"elementId":"4","text":"*********"}}
return: {"success":true,"data":true}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"true"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element, jsonBody: {"using":"id","value":"com.acp.aicaitencent:id/tvLogin"}
recive: {"cmd":"find","args":{"strategy":"id","selector":"com.acp.aicaitencent:id/tvLogin","multiple":false}}
return: {"success":true,"data":{"ELEMENT":"5"}}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"{\"ELEMENT\":\"5\"}"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: POST url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/element/5/click, jsonBody: {}
recive: {"cmd":"click","args":{"elementId":"5"}}
return: {"success":true,"data":true}
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0,"value":"true"}
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: GET url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0/screenshot, jsonBody: {}
>> responseHandler.js:50:12 [master] pid:10376 Send Error Respone to Client: Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-cm89un.png"
>> responseHandler.js:56:14 [master] pid:10376 Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-cm89un.png"
at ChildProcess.exithandler (child_process.js:213:12)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at maybeClose (internal/child_process.js:827:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb -s 192.168.236.101:5555 pull /data/local/tmp/screenshot.png C:\Users\cmd\AppData\Local\Temp\macaca-android-screenshot11679-10376-cm89un.png"
at ChildProcess.exithandler (child_process.js:213:12)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at maybeClose (internal/child_process.js:827:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
3) #5 Edit and Login
>> responseHandler.js:11:12 [master] pid:10376 Recieve HTTP Request from Client: method: DELETE url: /wd/hub/session/b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0, jsonBody: {}
>> macaca-android.js:60:14 [master] pid:10376 Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "D:\Android\android-sdk-windows/platform-tools/adb emu kill"
error: no emulator detected
at ChildProcess.exithandler (child_process.js:213:12)
at emitTwo (events.js:87:13)
at ChildProcess.emit (events.js:172:7)
at maybeClose (internal/child_process.js:827:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
>> session.js:80:12 [master] pid:10376 Delete session, sessionId: b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0
>> responseHandler.js:43:14 [master] pid:10376 Send HTTP Respone to Client: {"sessionId":"b7ff1a6b-c532-40fe-b5c8-074f24b2d0b0","status":0}
>>
>>
2 passing (1m)
3 failing
1) macaca mobile sample #2 should display 我的page:
Error: [takeScreenshot()] Not JSON response
at exports.newError (D:\macaca\me-app\node_modules\macaca-wd\wd\lib\utils.js:139:13)
at D:\macaca\me-app\node_modules\macaca-wd\wd\lib\callbacks.js:59:17
at D:\macaca\me-app\node_modules\macaca-wd\wd\lib\webdriver.js:179:5
at Request._callback (D:\macaca\me-app\node_modules\macaca-wd\wd\lib\http-utils.js:87:7)
at Request.self.callback (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:368:22)
at Request.<anonymous> (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:1219:14)
at IncomingMessage.<anonymous> (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:1167:12)
at endReadableNT (_stream_readable.js:921:12)
2) macaca mobile sample #4 should display 登录Page:
Error: [takeScreenshot()] Not JSON response
at exports.newError (D:\macaca\me-app\node_modules\macaca-wd\wd\lib\utils.js:139:13)
at D:\macaca\me-app\node_modules\macaca-wd\wd\lib\callbacks.js:59:17
at D:\macaca\me-app\node_modules\macaca-wd\wd\lib\webdriver.js:179:5
at Request._callback (D:\macaca\me-app\node_modules\macaca-wd\wd\lib\http-utils.js:87:7)
at Request.self.callback (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:368:22)
at Request.<anonymous> (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:1219:14)
at IncomingMessage.<anonymous> (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:1167:12)
at endReadableNT (_stream_readable.js:921:12)
3) macaca mobile sample #5 Edit and Login:
Error: [takeScreenshot()] Not JSON response
at exports.newError (D:\macaca\me-app\node_modules\macaca-wd\wd\lib\utils.js:139:13)
at D:\macaca\me-app\node_modules\macaca-wd\wd\lib\callbacks.js:59:17
at D:\macaca\me-app\node_modules\macaca-wd\wd\lib\webdriver.js:179:5
at Request._callback (D:\macaca\me-app\node_modules\macaca-wd\wd\lib\http-utils.js:87:7)
at Request.self.callback (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:368:22)
at Request.<anonymous> (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:1219:14)
at IncomingMessage.<anonymous> (D:\macaca\me-app\node_modules\macaca-wd\node_modules\request\request.js:1167:12)
at endReadableNT (_stream_readable.js:921:12)
>> Test completed!
以下为参考的文章,向作者表示感谢,提供了思路。
如何从头编写你的 Macaca 测试用例
编写移动端 Macaca 测试用例 [单步调试]
Macaca-iOS 入门那些事 2
[基于 Node.js 的自动化测试-Macaca] - 自动化测试实践总结