我们做自动化测试的时候,有的时候需要用模拟器来跑。 主要好处是:节约设备,不需要占用实际的设备资源;而且不会锁屏,需要充电等各种烦恼。 有的时候却用真机跑有好处,他们的区别是什么? 1.模拟器太慢
模拟器的运行速度取决于PC的配置,如果PC使用了机械硬盘那么使用模拟器光是启动的时间就够泡一壶茶了。
2.模拟器在某些方面往往达不到真机的真实水平。
碎片化严重。国内的手机厂商们热衷于对安卓系统进行深度定制,这也让开发者们操碎了心。小米、魅族、锤子这样的深度定制系统,应用开发好以后同样需要使用真实设备来适配。
3.模拟器不能模拟所有的API
Email、电话、短信等基于真实硬件的API由于模拟器本身的限制是不能被模拟出来的,因此应用但凡需要调用这些API的,都应该选择真机调试。
4.真机调试更能清晰真实的反映出开发过程中出现的问题;而模拟器性能比较差,在模拟器上不一定能发现。
5.真机测试更能支持横竖屏都方便,有一些情况模拟机不行。
6.搞3D图形图像时候,真机支持,虚拟机不一定支持OpenGL ES。
7.真机调试速度快,模拟器速度慢。
如果你对什么都没有要求,可以用模拟器来跑。如果你对上面列举的有要求,在资源允许的情况下,能用真机就用真机。
最近需要在真机上模拟用户的行为。然后考虑用Appium这个自动化测试框架来操作。
用Android 还好,一下就解决问题了。 代码类似如下:
current_path = os.path.dirname(os.path.abspath(__file__))
audio_file_path = os.path.join(current_path, "audio")
sentence_file = current_path + "\\sentence.txt"
result_path = current_path + "\\result"
log_path = current_path + "\\result\\log.txt"
import subprocess
def cmd(cmd):
return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def get_device():
for device in cmd('adb devices').stdout.readlines():
if 'devices' not in str(device):
device = device.decode('utf-8')
return device.split('\t')[0]
def get_version():
if cmd('adb shell getprop | findstr version.release').stdout != "":
result = cmd('adb shell getprop | findstr ro.build.version.release').stdout.readline()
result = str(result).split(":")[1]
return result[result.index("[") + 1:result.index("]")]
def get_brand():
if cmd('adb shell getprop | findstr ro.product.brand').stdout != "":
result = cmd('adb shell getprop | findstr ro.product.brand').stdout.readline()
result = str(result).split(":")[1]
return result[result.index("[") + 1:result.index("]")]
desired_caps = {}
desired_caps["platformName"] = "android"
desired_caps["platformVersion"] = get_version()
desired_caps["deviceName"] = get_device()
desired_caps["appPackage"] = "com.library.speechscoringsdk"
desired_caps["appActivity"] = "com.library.speechscoringsdk.RootActivity"
desired_caps["autoGrantPermissions"] = True
desired_caps["automationName"] = "UiAutomator1"
desired_caps["noReset"] = True
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
result = []
#
def wait_element_appear(driver, element):
try:
# 设置等待
wait = WebDriverWait(driver, element_time, DURATION)
# 使用匿名函数
wait.until(lambda diver: driver.find_element_by_id(element))
return True
except:
return False
def is_element_appear(driver, element):
try:
driver.find_element_by_id(element)
return True
except:
return False
Android真机跟模拟器没啥区别,只要你插上去的机器,都能获取device name 和版本号。
但是IOS的真机,就遇到了一些麻烦。弄了好久都没搞定。 启动,类似这样:
看来是没有装最新的WDA https://github.com/appium/appium/issues/13996
然后找了官方文档来读, http://appium.io/docs/en/drivers/ios-xcuitest-real-devices/ 就是要装一个一个WDA. WDA: WebDriverAgent is a WebDriver server implementation for iOS that can be used to remote control iOS devices. 最后在某个对测试有研究的老外开发的帮助下,折腾了好久,终于搞定了。 在某度上搜了好久,都不起作用,主要是都是以前的文档,某度上都会告诉你用一个免费的apple id就能搞定,实际则不然。可能苹果公司后面有限制了。
自动build WDA的方法 其实这种方法比较简单,就是你不需要自己手动去build WDA, 它自动帮你弄好。推荐用这种方法,主要是你codesign要搞正确,不行用buildleid, 这里举Appium-desktop为例子。 首先你得在你的mac上装最新的Appium-desktop, 不然不兼容。
然后配置文件可以这么写:
"automationName": "XCUITest",
"platformName": "ios",
"platformVersion": "12.4",
"deviceName": "Phone XS Max",
"bundleId": "com.EngageSpeechScoringSample",
"udid": "0000-00110D141492002E",
"xcodeOrgId": "8HX",
"xcodeSigningId": "iPhone Developer",
"updatedWDABundleId": "com.EngageSpeechScoringSample"
这些参数 "platformVersion", "deviceName, "udid" 可以在你插入的手机里面获得: You can find it in xcode. Window→Device and Similators
像是这样:
这个 "bundleId"就是你要测的App的标识符,如果不知道,请开发帮忙。 这个 "xcodeOrgId" 就是苹果开发者证书的id, 也可以找开发帮忙。
当所有的desired_caps 填好以后. 就可以启动Appium-desktop. 我开始老启动不起来,主要是updatedWDABundleId这里出了点问题,后来在老外的帮助下,加了这个字段,就搞定了。
第一次启动的时候,要花上几分钟,你可以看到log里面一直报错。那是在build WDA, 无法跟WDA通信。
最后,在你的测试机上会build成功一个WDA,你可以开始愉快的玩耍了。
手动Build WDA
手动的配置,就是你要手工去build一个WDA在你的测试机器上,
"automationName": "XCUITest",
"platformName": "ios",
"platformVersion": "12.4",
"deviceName": "Phone XS Max",
"bundleId": "com.EngageSpeechScoringSample",
"udid": "8020-00110D141492002E",
"xcodeOrgId": "8HHX",
"xcodeSigningId": "iPhone Developer",
首先,你得在xcode登录苹果开发者账号,哪怕用个人team, 网上教程都是用免费的,现在免费的好像不灵了。 查看一下账号 Xcode. Xcode-->Preferance
然后去clone开源代码, 当然你也可以看网上教程,去appium内部module下去编译。个人觉得开源代码更新更靠谱一些。 https://github.com/facebookarchive/WebDriverAgent
然后CD到项目路径下,运行
./Scripts/bootstrap.sh
然后就是改WebdriverAngentLib and WebdriverAgentRunner 中的team, bundle ID, 把facebook的都改成你自己的。 我在开发电脑上一次性就搞好了。
然后Test, 最终在你的测试机上就会编译成功一个WDA. 也可以查命令:
Open /usr/local/lib/node_modules/appium/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj
cd cd /usr/local/lib/node_modules/appium/node_modules/appium-webdriveragent/
xcodebuild -project WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=00008030-000145601EF0802E' test
成功以后,就可以开始你的测试了。
当然,IOS里面没有adb命令,你可以用自己封装的一些命令来操作,也可以达到效果。
brew install --HEAD libimobiledevice
brew install --HEAD ideviceinstaller
idevice_id -l #显示当前所连接的设备[udid],包括 usb、WiFi 连接
ideviceinstalller -i xx.ipa
# 查看应用的bundleId
andersons-iMac:~ anderson$ ideviceinstaller -l
如果报错:
Could not connect to lockdownd. Exiting.
重新编译就可以解决:
1 brew uninstall -f libimobiledevice ideviceinstaller usbmuxd
如果失败执行:
brew uninstall --ignore-dependencies libimobiledevice ideviceinstaller usbmuxd
2 brew install -v --HEAD --fetch --build-from-source usbmuxd libimobiledevice ideviceinstaller
更多命令,需要自己平时总结。我这里写一个例子:
from playsound import playsound
TIME_OUT = 30
TIMES = 30
element_max_wait_time = 10
DURATION = 0.5
SLEEPTIME = 13
current_path = os.path.dirname(os.path.abspath(__file__))
audio_file_path = os.path.join(current_path, "audio")
sentence_file = current_path + "/sentence.txt"
result_path = current_path + "/result"
log_path = current_path + "/result/log.txt"
import subprocess
def cmd(cmd):
return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def get_device_udid():
if cmd('idevice_id -l').stdout != "":
result = cmd('idevice_id -l').stdout.readline()
return result.decode("utf-8").strip()
def get_version():
if cmd('ideviceinfo -k ProductVersion').stdout != "":
result = cmd('ideviceinfo -k ProductVersion').stdout.readline()
return result.decode("utf-8").strip()
def get_device_show_name():
if cmd('idevicename').stdout != "":
result = cmd('idevicename').stdout.readline()
return result.decode("utf-8").strip()
def get_device_name():
if cmd('ideviceinfo -k ProductType').stdout != "":
result = cmd('ideviceinfo -k ProductType').stdout.readline()
return result.decode("utf-8").strip()
desired_caps = {}
desired_caps["automationName"] = "XCUITest"
desired_caps["platformName"] = "ios"
desired_caps["platformVersion"] = get_version()
desired_caps["udid"] = get_device_udid()
desired_caps["deviceName"] = get_device_name()
desired_caps["bundleId"] = "com.SpeechScoringSample"
desired_caps["xcodeOrgId"] = "HHX"
desired_caps["xcodeSigningId"] = "iPhone Developer"
desired_caps["updatedWDABundleId"] = "com.SpeechScoringSample"
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
result = []
def play_audio(mp3):
playsound(mp3)
def is_element_appear(driver, element):
try:
driver.find_element_by_accessibility_id(element)
return True
except:
return False
def wait_element_appear(driver, element):
try:
wait = WebDriverWait(driver,element_max_wait_time,DURATION)
wait.until(lambda driver: driver.find_element_by_accessibility_id(element))
return True
except:
return False
其他的就是业务上的累积了,我就不在这里写了。