Macaca 自动化框架 [Python 系列]

时间:2023-01-08 11:22:38

或可直接查询testerhome发表的文章: https://testerhome.com/topics/7898

介绍

Macaca是一套完整的自动化测试解决方案,基于node.js开发。由阿里巴巴公司开源:

地址:https://github.com/macacajs/

特点:

同时支持PC端和移动端(Android、iOS)自动化测试。

支持JavaScript(Node.js)、Java、Python。

前置准备

安装Java

Java下载地址:(http://www.java.com/zh_CN/download/manual.jsp)

打开下载链接选择相应的版本进行下载。我们以Windows安装JDK为例,

双击下载的JDK ,设置安装路径。这里我选择默认安装在:

D:\Program Files (x86)\Java\jdk1.8.0_25\目录下。

下面设置环境变量:

【我的电脑】->右键菜单--->属性--->高级--->环境变量--->系统变量-->新建:

变量名:JAVA_HOME

变量值:D:\Program Files (x86)\Java\jdk1.8.0_25

变量名:CALSS_PATH

变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

找到path变量名—>“编辑”添加:

变量名:PATH

变量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

安装Ant构建工具

Apache Ant,是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发。

下载地址:http://ant.apache.org/manualdownload.cgi

下载zip包之后解压,我的解压位置为:D:\java\apache-ant

然后,将该目录添加到环境变量path下面。

变量名:PATH

变量值:D:\java\apache-ant\bin;

安装Android SDK

Android SDK提供了你的API库和开发工具构建,测试和调试应用程序

官方地址:(http://developer.android.com)

如果无法下载,你也可以通过该地址下载Studio与SDK。

下载地址: (http://www.android-studio.org/index.php/download)

如果只是想运行Android模拟器,单独下载SDK也可以。

Android SDK(Windows)百度网盘下载地址:(http://pan.baidu.com/s/1kVOvxEB)

下面设置环境变量:

【我的电脑】右键菜单--->属性--->高级--->环境变量--->系统变量-->新建..

变量名:ANDROID_HOME

变量值:D:\android\android-sdk-windows (以本机为主)

找到path变量名—>“编辑”添加:

变量名:PATH

变量值:;%ANDROID_HOME%\platform-tools;%ANDROID_HOME%\tools;

iOS前置准备

Macaca环境安装

1、Macaca由Node.js开发,所以需要安装Node.js。

地址:https://nodejs.org/en/

2、安装Node.js完成。 首先切换切换淘宝源,因为国外资源访问很慢,而且有些资源还无法下载。

  • npm install -g cnpm --registry=https://registry.npm.taobao.org

3、通过淘宝源安装 macaca-cli

  • cnpm i macaca-cli -g

4、安装webdriver-client

  • cnpm install webdriver-client

5、安装macaca-electron

  • cnpm install macaca-electron -g

macaca-electron是基于Electron开发的Macaca驱动,是Macaca驱动之一。

6、安装macaca-chrome

  • cnpm install macaca-chrome -g

7、安装Macaca Python Client,支持pip安装。

下载地址:https://pypi.python.org/pypi/wd

  • python3 -m pip install wd

8、安装macaca-chromedriver

  • cnpm install macaca-chromedriver -g

9、安装macaca-android

  • cnpm install macaca-android -g

10、安装macaca-ios

  • cnpm i macaca-ios -g

注意事项

1、npm方式安装慢的问题

  • npm install -g cnpm --registry=http://r.cnpmjs.org (或用淘宝镜像:registry = https://registry.npm.taobao.org)
  • 或者先安装cnpm,再用cnpm代替npm命令 (安装cnpm方式,请参照上述)

2、切换源方式

按快捷键【Win+X】 --> 选择“提示命令符(管理员)A”,打开超级管理员权限的cmd命令窗口,

输入命令:“npm config set registry https://registry.npm.taobao.orgnpm

回车,即可跟换源,输入命令“ config get registry ”回车可以查看更换是否成功

3、安装chromedriver超时失败

  • npm install -g chromedriver --chromedriver_cdnurl=http://chromedriver.storage.googleapis.com
  • 或者 npm install -g chromedriver --chromedriver_cdnurl=http://npm.taobao.org/mirrors/chromedriver

官网示例

启动

启动Macaca服务

  • macaca server --verbose 【加--verbose,打印详细日志】
  • python tests/macaca-desktop-sample.test.py 【运行测试】

常用命令

安装

  • npm i macaca-cl -g

服务端

  • macaca server (正常模式)
  • macaca server -p 3456 (设置端口)
  • macaca server -p 3456 & (设置端口后台运行)
  • macaca server --verbose(输出详细日志)

测试

  • macaca run (运行当前目录用例集)
  • macaca run -d ./test (运行指定目录下用例集)

检查

  • macaca doctor (环境检查)

帮助

  • macaca -h
  • macaca server -h
  • macaca run -h
  • macaca doctor -h

代码

  • macaca electron示例
import unittest
import time
from macaca import WebDriver desired_caps = {
'platformName': 'desktop',
'browserName': 'electron'
} server_url = {
'hostname': 'localhost',
'port': 3456
} class MacacaTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = WebDriver(desired_caps, server_url)
cls.driver.init() @classmethod
def tearDownClass(cls):
cls.driver.quit() def test_get_url(self):
self.driver \
.set_window_size(1280, 800) \
.get('https://www.baidu.com') def test_search_macaca(self):
self.driver \
.element_by_id('kw') \
.send_keys('macaca')
self.driver \
.element_by_id('su') \
.click()
time.sleep(3)
html = self.driver.source
self.assertTrue('macaca' in html)
self.assertTrue(
self.driver.element_by_css_selector_if_exists(
'#head > div.head_wrapper'))
self.driver \
.element_by_xpath_or_none('//*[@id="kw"]') \
.send_keys(' elementByXPath')
self.driver \
.element_by_id('su') \
.click()
self.driver.take_screenshot() if __name__ == '__main__':
unittest.main()
  • chrome 示例
#coding=utf-8
import unittest
from macaca import WebDriver
from time import sleep desired_caps = {
'platformName': 'Desktop', #// iOS, Android, Desktop
'browserName': 'Chrome', #// Chrome, Electron
} # 对应Macaca服务的ip和端口号。
server_url = {
'hostname': '127.0.0.1',
'port': 3456
} class MacacaTest(unittest.TestCase): @classmethod
def setUpClass(cls):
cls.driver = WebDriver(desired_caps, server_url)
cls.driver.init() @classmethod
def tearDownClass(cls):
cls.driver.quit() def test_get_url(self):
self.driver.get('https://www.baidu.com')
self.assertEqual(self.driver.title, '百度一下,你就知道') def test_search_macaca(self):
self.driver.element_by_id("kw").send_keys("macaca")
self.driver.element_by_id("su").click()
sleep(2)
title = self.driver.title
self.assertTrue('macaca',title) if __name__ == '__main__':
unittest.main()
  • android示例
#coding=utf-8
import unittest
import os
import time
from macaca import WebDriver desired_caps = {
'platformName': 'android',
'app': 'https://npmcdn.com/android-app-bootstrap@latest/android_app_bootstrap/build/outputs/apk/android_app_bootstrap-debug.apk',
'reuse': 3
} server_url = {
'hostname': 'localhost',
'port': 3456
} def switch_to_webview(driver):
contexts = driver.contexts
driver.context = contexts[-1]
return driver def switch_to_native(driver):
contexts = driver.contexts
driver.context = contexts[0]
return driver class MacacaTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = WebDriver(desired_caps, server_url)
cls.driver.init() @classmethod
def tearDownClass(cls):
cls.driver.quit() def test_01_login(self):
self.driver \
.element_by_xpath('//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.RelativeLayout[1]/android.widget.EditText[1]') \
.send_keys('中文+Test+12345678') \ els = self.driver \
.elements_by_class_name('android.widget.EditText') els[1].send_keys('111111') self.driver \
.element_by_name('Login') \
.click() def test_02_scroll_tableview(self):
self.driver \
.element_by_name('HOME') \
.click() self.driver \
.element_by_name('list') \
.click() def test_03_gesture(self):
self.driver \
.touch('drag', {
'fromX': 200,
'fromY': 400,
'toX': 200,
'toY': 100,
'steps': 50
}) time.sleep(1) self.driver \
.touch('drag', {
'fromX': 100,
'fromY': 100,
'toX': 100,
'toY': 400,
'steps': 50
}) self.driver \
.element_by_name('Alert') \
.click() time.sleep(1) self.driver \
.accept_alert() \
.back() time.sleep(1) self.driver \
.element_by_name('Gesture') \
.click() self.driver \
.touch('tap', {
'x': 100,
'y': 100
}) time.sleep(1) self.driver \
.touch('doubleTap', {
'x': 100,
'y': 100
}) time.sleep(1) self.driver \
.touch('press', {
'x': 100,
'y': 100,
'steps': 100
}) time.sleep(1) self.driver \
.element_by_id('com.github.android_app_bootstrap:id/info') \
.touch('pinch', {
'percent': 200,
'steps': 200
}) time.sleep(1) self.driver \
.touch('drag', {
'fromX': 100,
'fromY': 100,
'toX': 100,
'toY': 600,
'steps': 100
}) def test_04_webview(self):
self.driver \
.element_by_name('Webview') \
.click() time.sleep(3)
self.driver.save_screenshot('./webView.png') # save screen shot switch_to_webview(self.driver) \
.element_by_id('pushView') \
.touch('tap') switch_to_webview(self.driver) \
.element_by_id('popView') \
.touch('tap') def test_05_web(self):
switch_to_native(self.driver) \
.element_by_name('Baidu') \
.touch('tap') time.sleep(3)
self.driver.save_screenshot("./baidu.png") switch_to_webview(self.driver) \
.element_by_id('index-kw') \
.send_keys('macaca') self.driver \
.element_by_id('index-bn') \
.touch('tap') def test_06_logout(self):
switch_to_native(self.driver) \
.element_by_name('PERSONAL') \
.click() self.driver.element_by_name('Logout') \
.click() if __name__ == '__main__':
unittest.main()
  • android示例【简精版】
#coding=utf-8
import unittest
import time
from macaca import WebDriver desired_caps = {
'platformName': 'Android', # iOS, Android, Desktop
#'browserName': 'Chrome', # Chrome, Electron
"package": "com.huawei.iptv.stb",
"activity": "com.huawei.iptv.stb.ui.HeadTabActivity",
"deviceName":"192.168.1.105:5555",
} server_url = {
'hostname': '127.0.0.1',
'port': 3456
} class MacacaTest(unittest.TestCase):
def setUp(self):
self.driver = WebDriver(desired_caps, server_url)
self.driver.init() def tearDown(self):
self.driver.quit() def test_macaca(self):
el=self.driver.element_by_name("直播")
el.click()
time.sleep(2) if __name__ == '__main__':
unittest.main()
  • iOS示例
import unittest
import os
import time
from macaca import WebDriver desired_caps = {
'platformName': 'iOS',
'platformVersion': '10.0',
'deviceName': 'iPhone 5s',
'app': 'https://npmcdn.com/ios-app-bootstrap@latest/build/ios-app-bootstrap.zip',
} server_url = {
'hostname': 'localhost',
'port': 3456
} def switch_to_webview(driver):
contexts = driver.contexts
driver.context = contexts[-1]
return driver def switch_to_native(driver):
contexts = driver.contexts
driver.context = contexts[0]
return driver class MacacaTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = WebDriver(desired_caps, server_url)
cls.driver.init() @classmethod
def tearDownClass(cls):
cls.driver.quit() def test_01_login(self):
self.driver \
.element_by_xpath('//XCUIElementTypeTextField[1]') \
.send_keys('中文+Test+12345678') \ self.driver \
.element_by_xpath('//XCUIElementTypeSecureTextField[1]') \
.send_keys('111111') \ self.driver \
.element_by_name('Login') \
.click() def test_02_scroll_tableview(self):
self.driver \
.element_by_name('HOME') \
.click() self.driver \
.element_by_name('list') \
.click() def test_03_gesture(self):
self.driver \
.touch('drag', {
'fromX': 200,
'fromY': 400,
'toX': 200,
'toY': 100,
'duration': 2
}) time.sleep(1) self.driver \
.touch('drag', {
'fromX': 100,
'fromY': 100,
'toX': 100,
'toY': 400,
'duration': 2
}) self.driver \
.element_by_name('Alert') \
.click() time.sleep(1) driver \
.accept_alert() \
.back() time.sleep(1) self.driver \
.element_by_name('Gesture') \
.click() self.driver \
.touch('tap', {
'x': 100,
'y': 100
}) time.sleep(1) self.driver \
.touch('doubleTap', {
'x': 100,
'y': 100
}) time.sleep(1) self.driver \
.touch('press', {
'x': 100,
'y': 100,
'duration': 1
}) time.sleep(1) self.driver \
.element_by_id('info') \
.touch('pinch', {
'scale': 2,
'velocity': 1
}) time.sleep(1) self.driver \
.touch('drag', {
'fromX': 100,
'fromY': 100,
'toX': 100,
'toY': 600,
'steps': 100
}) def test_04_webview(self):
self.driver \
.element_by_name('Webview') \
.click() time.sleep(3)
self.driver.save_screenshot('./webView.png') # save screen shot switch_to_webview(self.driver) \
.element_by_id('pushView') \
.touch('tap') switch_to_webview(self.driver) \
.element_by_id('popView') \
.touch('tap') def test_05_web(self):
switch_to_native(self.driver) \
.element_by_name('Baidu') \
.touch('tap') time.sleep(3)
self.driver.save_screenshot("./baidu.png") switch_to_webview(self.driver) \
.element_by_id('index-kw') \
.send_keys('macaca') \
.element_by_id('index-bn') \
.touch('tap') def test_06_logout(self):
switch_to_native(self.driver) \
.element_by_name('PERSONAL') \
.click() self.driver.element_by_name('Logout') \
.click() if __name__ == '__main__':
unittest.main()

结束语