aapt dump badging xxx.apk
下图中框起来的即为appPackage
往下拉,找到launchable-activity,即为appActivity
adb devices #查看模拟器地址
appium
IDE:我用的vscode,推荐使用pycharm
我们采用page object的架构
建个工程,叫appium
建几个二级文件夹 case、pages、util、log、result、report、log
顾名思义:
case 存放测试用例
pages 存放页面对象、方法
util 存放工具类,如日志
log 存放日志
result 存放测试结果,allure生成报告需要的测试结果
report 存放生成的allure测试报告
log 存放日志
注:建二级子目录后,pycharm会自动添加__init__.py,但是vscode不会,我们需要在case、pages、util目录下手动添加__init__.py
目的:这个demo的实现启动app、点击或者滑动一下
case目录下创建demo.py,键入如下内容:
# -*- encoding: utf-8 -*-
from appium import webdriver
import time
# apk参数
desired_caps = {
'platformName': 'Android',
'deviceName': '127.0.0.1:62001', # 手机设备名称,通过adb devices查看
'platformVersion': '5.1.1', # android系统的版本号
'appPackage': 'com.aiosign.dzonesign', # apk包名
# apk的launcherActivity
'appActivity': 'com.aiosign.dzonesign.view.AppStartActivity',
}
# 启动app
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
time.sleep(3)
# 我的app启动后是欢迎页,需要滑动
# 获取屏幕尺寸
sizes = driver.get_window_size()
# 滑动
driver.swipe(sizes.get('width')*0.9, sizes.get('height')*0.5, sizes.get('width')*0.2, sizes.get('height')*0.5)
整个应用大概分为这么几个页面:
所以,我们在pages目录下创建一个BasePage.py用来存放一些公用的方法,比如查找元素、查找一组元素、输入、左右上下滑动、截图等
再创建三个py文件分别为WelcomePage.py LoginPage.py MainPage.py,继承自BasePage.py,如下:
BasePage.py内容如下:
# -*- encoding: utf-8 -*-
'''
@File : BasePage.py
@Time : 2020/02/11 14:49:52
@Author : peace_su
@Version : 1.0
@Contact : [email protected]
@WebSite : https://me.csdn.net/u010098760
'''
# here put the import lib
from selenium.webdriver.support.wait import WebDriverWait
# from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
import time
from util.LoggingUtil import LoggingUtil
import logging
import datetime
class BasePage(object):
'''类注释
详细描述
Attributes:
属性说明
'''
def __init__(self, driver):
'''Class1类初始化方法
Args:
paramter1: 入参说明
paramter2: 入参说明
'''
self.driver = driver
LoggingUtil.setup_logging(LoggingUtil)
self.logger = logging.getLogger()
def find_element(self, *loc):
'''重写查找单个元素方法
'''
try:
WebDriverWait(self.driver, 5, 0.5).until(
EC.visibility_of_element_located(loc))
return self.driver.find_element(*loc)
except Exception:
# print('页面未找到元素')
self.logger.error('未找到元素:%s 请检查!' % loc[1])
screen_shot = self.get_screen('screen_shot/')
self.logger.error('已截图,路径:%s' % screen_shot)
def find_elements(self, *loc):
'''重写查找多个元素方法
'''
try:
WebDriverWait(self.driver, 5, 0.5).until(
EC.visibility_of_element_located(loc))
return self.driver.find_elements(*loc)
except AttributeError:
# print('页面未找到元素')
self.logger.error('未找到元素:%s 请检查!' % loc[1])
screen_shot = self.get_screen('screen_shot/')
self.logger.error('已截图,路径:%s' % screen_shot)
def send_keys(self, loc, vaule, clear_first=True, click_first=True):
'''重写send_keys方法
'''
try:
loc = getattr(self, "_%s" % loc) # getattr相当于实现self.loc
if click_first:
self.find_element(*loc).click()
if clear_first:
self.find_element(*loc).clear()
self.find_element(*loc).send_keys(vaule)
except AttributeError:
# print("页面中未能找到元素")
self.logger.error('未找到元素:%s 请检查!' % loc[1])
screen_shot = self.get_screen('screen_shot/')
self.logger.error('已截图,路径:%s' % screen_shot)
def is_toast_exist(self, text):
'''is toast exist, return True or False
:Agrs:
- text - 页面上看到的文本内容
:Usage:
is_toast_exist("看到的内容")
'''
try:
toast_loc = (By.XPATH, ".//*[contains(@text,'%s')]" % text)
WebDriverWait(self.driver, 5, 0.5).until(
EC.presence_of_element_located(toast_loc))
return True
except Exception as e:
print(e)
self.logger.error('未找到元素:%s 请检查!' % text)
screen_shot = self.get_screen('screen_shot/')
self.logger.error('已截图,路径:%s' % screen_shot)
return False
def is_element_exist(self, *loc):
try:
WebDriverWait(self.driver, 5, 0.5).until(
EC.visibility_of_element_located(loc))
self.driver.find_element(*loc)
return True
except Exception:
# print('页面未找到%s元素' % (loc))
self.logger.error('未找到元素:%s 请检查!' % loc[1])
screen_shot = self.get_screen('screen_shot/')
self.logger.error('已截图,路径:%s' % screen_shot)
return False
def get_size(self):
'''获取屏幕大小
'''
try:
size = self.driver.get_window_size()
return size
except Exception:
self.get_screen('screen_shot/')
return None
def swipe_to_left(self):
'''左滑
'''
window_size = self.get_size()
width = window_size.get("width")
height = window_size.get("height")
try:
self.driver.swipe(width*0.9, height*0.5, width*0.1, height*0.5)
time.sleep(0.5)
except Exception:
self.get_screen('screen_shot/')
# self.driver.swipe(x*0.9, y*0.5, x*0.1, y*0.5)
def swipe_to_right(self):
'''右滑
'''
window_size = self.get_size()
width = window_size.get("width")
height = window_size.get("height")
try:
self.driver.swipe(width*0.1, height*0.5, width*0.9, height*0.5)
time.sleep(0.5)
except Exception:
self.get_screen('screen_shot/')
def swipe_to_up(self):
'''上滑
'''
window_size = self.get_size()
width = window_size.get("width")
height = window_size.get("height")
try:
self.driver.swipe(width*0.5, height*0.9, width*0.5, height*0.1)
time.sleep(0.5)
except Exception:
self.get_screen('screen_shot/')
def swipe_to_down(self):
'''下滑、下拉刷新
'''
window_size = self.get_size()
width = window_size.get("width")
height = window_size.get("height")
try:
self.driver.swipe(width*0.5, height*0.4, width*0.5, height*0.9)
time.sleep(1)
except Exception:
self.get_screen('screen_shot/')
def get_screen(self, path):
'''截图
'''
now = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
screen_shot = path + 'a_' + now + '.png'
self.driver.get_screenshot_as_file(screen_shot)
return screen_shot
if __name__ == '__main__':
print(123)
WelcomePage.py内容如下:
# -*- encoding: utf-8 -*-
'''
@File : WelcomePage.py
@Time : 2020/02/11 14:49:29
@Author : peace_su
@Version : 1.0
@Contact : [email protected]
@WebSite : https://me.csdn.net/u010098760
'''
# here put the import lib
from selenium.webdriver.common.by import By
from pages.BasePage import BasePage
class WelcomePage(BasePage):
'''欢迎页面元素及方法
该类继承自BasePage类
Attributes:
属性说明
'''
# 立即体验 按钮
tiyan_button = (By.ID, 'com.aiosign.dzonesign:id/vStartNow')
# 登录 按钮
login_button = (By.ID, 'com.aiosign.dzonesign:id/btLoginUser')
# 注册 按钮
register_button = (By.ID, 'com.aiosign.dzonesign:id/btRegisterUser')
# 点击立即体验按钮
def click_tiyan_button(self):
self.find_element(*self.tiyan_button).click()
# 点击登录按钮
def click_login_button(self):
self.find_element(*self.login_button).click()
# 点击注册按钮
def click_register_button(self):
self.find_element(*self.register_button).click()
if __name__ == '__main__':
print(123)
LoginPage 和 MainPage内容略过
暂时略过
单元测试使用pytest
unittest无法集成allure,htmltestrunner的日志太难看了
在case目录下建个test_login.py,如下:
# -*- encoding: utf-8 -*-
'''
@File : test_login.py
@Time : 2020/03/05 14:28:40
@Author : peace_su
@Version : 1.0
@Contact : [email protected]
@WebSite : https://me.csdn.net/u010098760
'''
# here put the import lib
import sys
import os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
import pytest
from util.LoggingUtil import LoggingUtil
from pages.BasePage import BasePage
from pages.WelcomePage import WelcomePage
from pages.LoginPage import LoginPage
from pages.MainPage import MainPage
import logging
from appium import webdriver
import time
import allure
@allure.feature('测试登录功能')
class Test_login(object):
'''类注释
详细描述
Attributes:
属性说明
'''
def setup_method(self, method):
self.logging_util = LoggingUtil()
self.logging_util.setup_logging()
self.logger = logging.getLogger()
desired_caps = {
'platformName': 'Android',
# 'deviceName': '127.0.0.1:5554', # 手机设备名称,通过adb devices查看
'deviceName': '127.0.0.1:62001', # 手机设备名称,通过adb devices查看
'platformVersion': '5.1.1', # android系统的版本号
'appPackage': 'com.aiosign.dzonesign', # apk包名
# apk的launcherActivity
'appActivity': 'com.aiosign.dzonesign.view.AppStartActivity',
}
self.logger.info('启动app')
try:
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
time.sleep(3)
self.base_page = BasePage(self.driver)
self.welcome_page = WelcomePage(self.base_page)
self.login_page = LoginPage(self.base_page)
self.main_page = MainPage(self.base_page)
except Exception:
BasePage.get_screen('screen_shot/')
def teardown_method(self, method):
print("断开连接")
@allure.story('登录-用户不存在')
def test_login_1(self):
self.logger.info('开始测试test_login_1==================================')
self.base_page.swipe_to_left()
self.base_page.swipe_to_left()
self.welcome_page.click_tiyan_button()
self.welcome_page.click_login_button()
self.login_page.input_username('15628811988')
self.login_page.input_passwd('12345678')
self.login_page.click_signin_button()
res = self.base_page.is_toast_exist('用户不存在')
assert res
self.logger.info('测试结束=====================================')
@allure.story('登录-账号或密码错误')
def test_login_2(self):
self.base_page.swipe_to_left()
self.base_page.swipe_to_left()
self.welcome_page.click_tiyan_button()
self.welcome_page.click_login_button()
self.login_page.input_username('123456')
self.login_page.input_passwd('abc23')
self.login_page.click_signin_button()
res = self.base_page.is_toast_exist('账号或密码错误')
assert res
@allure.story('登录-正常')
def test_right(self):
self.logger.info('开始测试test_right=====================================')
self.base_page.swipe_to_left()
self.base_page.swipe_to_left()
self.welcome_page.click_tiyan_button()
self.welcome_page.click_login_button()
self.login_page.input_username('123456')
self.login_page.input_passwd('abcabc')
self.login_page.click_signin_button()
res = self.main_page.is_personal_center_button_exist()
assert res
# self.main_page.click_personal_center_button()
# self.logger.info('测试完成')
@allure.story('登录-未输入密码')
def test_login_3(self):
self.base_page.swipe_to_left()
self.base_page.swipe_to_left()
self.welcome_page.click_tiyan_button()
self.welcome_page.click_login_button()
self.login_page.input_username('123456')
# self.login_page.input_passwd('')
self.login_page.click_signin_button()
res = self.base_page.is_toast_exist('请输入密码!')
assert res
@allure.story('登录-账号格式不正确')
def test_login_4(self):
self.base_page.swipe_to_left()
self.base_page.swipe_to_left()
self.welcome_page.click_tiyan_button()
self.welcome_page.click_login_button()
self.login_page.input_username('156288119')
self.login_page.input_passwd('abcabc')
self.login_page.click_signin_button()
res = self.base_page.is_toast_exist('账号格式不正确(邮箱、信用代码、手机)')
assert res
@allure.story('登录-未输入账号')
def test_login_5(self):
self.base_page.swipe_to_left()
self.base_page.swipe_to_left()
self.welcome_page.click_tiyan_button()
self.welcome_page.click_login_button()
# self.login_page.input_username('')
self.login_page.input_passwd('abcabc')
self.login_page.click_signin_button()
res = self.base_page.is_toast_exist('请输入账号!')
assert res
if __name__ == '__main__':
pytest.main(["--reruns", "3", "--reruns-delay", "2", "--alluredir", "result"])
运行此文件,控制台输出执行情况,如下:
别忘了启动appium和模拟器哦,在模拟器里预先安装好待测试的apk
其中.是测试通过的,R是重试的,F是失败的,E是出现异常的
在cmd中执行如下命令,生成测试报告:
allure generate result -o report --clean
接下来,我们需要去vscode中找到report目录下的index.html,用live server打开
pycharm中右键,用浏览器打开即可
直接在文件夹中双击index.html在浏览器中打开不行哦
报告如下:
可以点击各个具体的菜单,查看具体信息。
至此,一个大的架子基本搭建完成了。