本贴是初步的粗略整理出来的成果,难免会有遗漏,如果同学们发现重要命令或者url遗漏,请联系助教进行补充。
Linux与shell三剑客
1、Linux系统与shell环境准备
ls: 列出目录
cd:切换目录
pwd:显示目前的目录
mkdir:创建一个新的目录
rmdir:删除一个空的目录
cp: 复制文件或目录
rm: 移除文件或目录
mv: 移动文件与目录,或修改文件与目录的名称
Shell基础
常见的shell
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh
运行shell
-
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本 -
/bin/sh test.sh
Linux常用命令
文件
ls: 列出目录
cd:切换目录
pwd:显示目前的目录
mkdir:创建一个新的目录
rmdir:删除一个空的目录
cp: 复制文件或目录
rm: 移除文件或目录
mv: 移动文件与目录,或修改文件与目录的名称
文件权限
r 读权限read 4
w 写权限write 2
x 操作权限execute 1
chmod 777 test,修改test文件属性
网络
netstat:打印Linux网络系统的状态信息
-t 列出所有tcp
-u 列出所有udp
-l 只显示监听端口
-n 以数字形式显示地址和端口号
-p 显示进程的pid和名字
性能
top:持续监视系统性能
ps:查看进程信息
-aux 显示所有进程,包括用户,分组情况
3、Linux三剑客与管道使用
管道
Linux提供管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入
正则
正则表达式就是记录文本规则的代码
演练环境
举例
找出所有的hi单词 \bhi\b
hi单词后面有lucy单词 \bhi\b.*\blucy\b
以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字 0\d{2}-\d{8}
grep
根据用户指定的模式(pattern)对目标文本进行过滤,显示被模式匹配到的行
选项
-v 显示不被pattern匹配到的行
-i 忽略字符大小写
-n 显示匹配的行号
-c 统计匹配的行数
-o 仅显示匹配到的字符串
-E 使用ERE,相当于egrep
sed
sed是流编辑器,一次处理一行内容
sed [-hn…][-e][-f<script文件>][文本文件]
-h 显示帮助。
-n 仅显示script处理后的结果。
sed [-hnV][-e][-f<script文件>][文本文件]
-e 以选项中指定的script来处理输入的文本文件。
-f<script文件> 以选项中指定的script文件来处理输入的文本文件。
a :新增 sed -e ‘4 a newline’
c :取代 sed -e ‘2,5c No 2-5 number’
d :删除 sed -e '2,5d’
i :插入 sed -e ‘2i newline’
p :打印 sed -n ‘/root/p’
s :取代 sed -e 's/old/new/g’
awk
把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行后续处理
awk ‘pattern + action’ [filenames]
-pattern 正则表达式
-action 对匹配到的内容执行的命令(默认为输出每行内容)
FILENAME awk浏览的文件名
BEGIN 处理文本之前要执行的操作
END 处理文本之后要执行的操作
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数(列数)
NR 已读的记录数(行数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
$0 整条记录
$1 表示当前行的第一个域…以此类推
Bash编程语法
变量
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
中间不能有空格,可以使用下划线(_)
不能使用标点符号
不能使用bash里的关键字(可用help命令查看保留关键字)
变量类型
字符串:your_name=“hogwarts”
拼接字符串:greeting=“hello, “$your_name” !”
数组 array_name=(value0 value1 value2 value3)
取数组 valuen=${array_name[n]}
单独赋值 array_name[0]=value0
控制语句
if
比较两个变量的大小并输出不同的值
i f [ $a -eq $b ]; then echo “equal”; elif [ $a -lt $b ];then echo “small”; elif [ $a -gt $b ];then echo “big”;fi
for
循环读取文件内容并输出
for i in $(cat dir.txt);do echo $i;done
while
循环读取文件内容并输出
while read line;do echo $line;done<dir.txt
Bash脚本编写
read
read命令是用于从终端或者文件中读取输入的内部命令
读取整行输入
每行末尾的换行符不被读入
使用
从标准输入读取输入并赋值给变量
read var
从标准输入读取多个内容
read var1 var2 var3
不指定变量(默认赋值给REPLY)
read
脚本传参
$0 脚本名称
$1~$n 获取参数
$# 传递到脚本的参数个数
$$ 脚本运行的当前进程ID号
$* 以一个单字符串显示所有向脚本传递的参数
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误
算数运算
a=10 b=20
+ 加法 `expr $a + $b` 结果为 30
- 减法 `expr $a - $b` 结果为 -10
* 乘法 `expr $a \* $b` 结果为 200
/ 除法 `expr $b / $a` 结果为 2
a=10 b=20
% 取余 `expr $a % $b` 结果为 10
= 赋值 a=$b 将把变量 b 的值赋给 a
== 相等 相同则返回 true:[ $a == $b ] 返回 false
!= 不相等 不相同则返回 true:[ $a != $b ] 返回 true
-eq 检测相等 [ $a -eq $b ] 返回 false
-ne 检测不相等 [ $a -ne $b ] 返回 true
-gt 检测左边是否大于右边 [ $a -gt $b ] 返回 false
-lt 检测左边是否小于右边 [ $a -lt $b ] 返回 true
-ge 检测左边是否大于等于右边 [ $a -ge $b ] 返回 false
-le 检测左边是否小于等于右边 [ $a -le $b ] 返回 true
数据库
sql
SQL下载地址
https://dev.mysql.com/downloads/mysql/
工作库下载地址
内连接查询 inner join
select * from a_table a inner join b_table b on a.a_id = b.b_id
左连接查询 left join
SELECT * FROM a_table a left join b_table b ON a.a_id = b.b_id
右连接 right join
SELECT * FROM a_table a right outer join b_table b on a.a_id = b.b_id
redis
redis下载地址
https://github.com/microsoftarchive/redis/releases
java使用redis引入依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
Java使用Redis-创建Jedis实例
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost");
jedis.auth("hogwarts");//此处为你设置的密码
System.out.println("连接成功");
//查看服务是否运行
System.out.println("服务正在运行: "+jedis.ping());
Selenium
官方网站
driver
driver介绍
https://www.selenium.dev/documentation/en/webdriver/driver_requirements/
driver下载
淘宝镜像:CNPM Binaries Mirror
官方网站:https://chromedriver.storage.googleapis.com/index.html
driver安装
找到和自己浏览器版本适配的driver版本 ChromeDriver - WebDriver for Chrome - Version Selection
SeleniumIDE
IDE下载
Chrome插件:
https://chrome.google.com/webstore/detail/selenium-ide/mooikfkahbdckldjjndioackbalphokd
Firefox插件:
代码导出与常见问题
代码导出:
常见问题:
web控件交互进阶
Actions
官方文档:Generated Documentation (Untitled)
用法
具体写法:
链式写法
Actions actions=new Actions(driver).moveToElement(ele).click().perform(ele);
分布写法
Actions actions =new Actions(driver);
actions.move_to_element(element)
actions.click(element)
actions.perform()
拖拽练习网址
http://sahitest.com/demo/dragDropMooTools.htm
按键练习网址
http://sahitest.com/demo/label.htm
多窗口处理
https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable
代码
@Test
public void frameTest() {
try {
driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable");
driver.switchTo().frame("iframeResult");
System.out.println(driver.findElement(By.id("draggable")).getText());
driver.switchTo().parentFrame();
driver.switchTo().parentFrame();
driver.findElement(By.id("submitBTN")).click();
System.out.println(driver.findElement(By.id("submitBTN")).getText());
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
多浏览器支持
代码
public static WebDriver driver;
@BeforeAll
public static void initData(){
String browserName= System.getenv("browser");
if(browserName.equals("chrome")){
System.setProperty("webdriver.chrome.driver","/Users/naruto0728/Downloads/chromedriver");
driver=new ChromeDriver();
}else if(browserName.equals("firefox")){
System.setProperty("webdriver.gecko.driver","/Users/naruto0728/Downloads/geckodriver");
driver = new FirefoxDriver();
}
}
@Test
public void fun(){
driver.get("https://home.testing-studio.com");
}
@AfterAll
public static void tearDown(){
driver.quit();
执行js脚本
例如js代码:
window.alert(‘Selenium弹框测试')
a = document.getElementById(‘kw’).value
document.title
selenium如何调用js,selenium提供了一个内置 的方法execute_script()
driver.execute_script("window.alert('Selenium弹框测试')")
driver.execute_script("a = document.getElementById(‘kw’).value;window.alert(a)”)
如何返回呢?
driver.execute_script("return document.getElementById('kw').value")
文件上传与弹框处理
文件上传
driver.findElement(By.xpath(“xxx”)).sendKeys(“路径”)
弹框处理
网址:
https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable
代码
@Test
public void fun() {
try {
driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable");
Actions actions = new Actions(driver);
driver.switchTo().frame("iframeResult");
actions.dragAndDrop(driver.findElement(By.id("draggable")),
driver.findElement(By.id("droppable"))).perform();
driver.switchTo().alert().accept();
driver.switchTo().parentFrame();
driver.findElement(By.id("submitBTN")).click();
} catch (Exception e) {
e.printStackTrace();
}
}
PO设计模式
PO设计模式历史
2013 Martin Flower PageObject
2015 Selenium https://github.com/SeleniumHQ/ selenium/wiki/PageObjects
2020 /documentation/test_practices/encouraged/page_object_models/
Appium
github地址:https://github.com/appium
appium环境安装
JDK
JDK1.8下载地址
http://www.oracle.com/technetwork/java/javase/downloads/index.html
安装(一直点下一步-〉完成,用默认的路径即可)
配置环境变量(windows)
JAVA_HOME D:\Android\Java\jdk1.8.0_25 (注意这里面的JAVA_HOME大写后面会用到)
classpath .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;(最前面加个点和分号 .;)
path %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
检查JAVA环境是否配置好
进入命令行,输入java -version 或javac -version,输出版本号信息即成功。
安装SDK
下载sdk
Android studio地址
https://developer.android.com/studio/index.html
中文官网下载地址:http://tools.android-studio.org/index.php/sdk
安装sdk
其实sdk就是个文件夹,下载之后需要手动更新, 配上环境变量就可以使用,不需要手动安装
配置android SDK环境变量,如下:
ANDROID_HOME D:\adt-bundle-mac-x86_64-20140702\sdk
PATH %ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools
检查是否安装成功,cmd输出
adb回车或者adb shell 然后回车
appium环境安装
安装appium desktop (appium server + appium inspector工具)
下载对应操作系统的安装包:https://github.com/appium/appium-desktop/releases
如果不需要appium inspector ,也可以通过 npm直接安装appium
官方安装(不推荐)
npm install -g appium
淘宝提供(推荐)
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g appium
运行
appium (不报错说明安装成功)
安装appium python client
方式一:Pip install appium-python-client(推荐)
方式二:下载源码包:
下载地址:https://github.com/appium/python-client
https://pypi.python.org/pypi/Appium-Python-Client
解压后在命令行中进入python-client-master目录,该目录下包含setup.py文件
执行命令python setup.py install命令安装客户端
安装appium doctor
cnpm install appium-doctor
运行测试用例
from appium import webdriver
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['platformVersion']='6.0'
desired_caps['deviceName']='emulator-5554'
desired_caps['appPackage']='com.android.settings'
desired_caps['appActivity']='com.android.settings.Settings'
driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
driver.quit()
appium元素定位与隐式等待
Capability设置
appActivity Activity名字
adb logcat | grep ActivityManager
adb shell dumpsys activity activities | grep mFocusedActivity
aapt dumpsys badging com.android.chrome.apk |grep 'launchable-activity'
官方文档:
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
app控件定位
定位方式:
id定位
driver.findElement(By.id("xxx"))(resource-id属性值)
accessibility_id定位
driver.findElement(MobileBy.AccessibilityId("xxx"));(content-desc属性值)
xpath定位
driver.findElement(By.xpath("xxx"))(xpath 属性值)
classname定位(不推荐)
Free Online XPath Tester / Evaluator - FreeFormatter.com #ad-output格式化xml
app控件交互
get_attribute()方法能获取的属性,元素的属性几乎都能获取到,属性名称和 uiautomatorviewer 里面的一致
高级定位技巧
Xpath定位
https://www.w3school.com.cn/xpath/xpath_syntax.asp
实例演示
public void priceTest() {
//定位首页搜索框
driver.findElement(By.id("com.xueqiu.android:id/home_search")).click();
//定位搜索页搜索框
driver.findElement(By.id("com.xueqiu.android:id/search_input_text")).sendKeys("阿里巴巴");
//
driver.findElement(By.xpath("//*[@text='BABA']")).click();
driver.findElement(By.xpath("//*[@resource-id='com.xueqiu.android:id/title_text'][@text='股票']")).click();
System.out.println(
driver.findElement(By.xpath("//*[@text='09988']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']")).getText()
);
}
uiautomator定位
https://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html
表达式
((AndroidDriver<MobileElement>)driver).findElementByAndroidUIAutomator(表达式).click()
组合定位
id与text属性组合
String id_text = 'resourceId("com.xueqiu.android:id/tab_name").text("交易")'
driver.findElementByAndroidUIAutomator(id_text).click()
class与text属性组合
String class_text = 'className("android.widget.TextView").text("行情")'
driver.findElementByAndroidUIAutomator(class_text).click()
父子关系定位 childSelector
son = 'resourceId("com.xueqiu.android:id/scroll_view").childSelector(text("热门"))'
兄弟定位 fromParent
brother = 'resourceId("com.xueqiu.android:id/tab_name").fromParent(text("我的"))'
实现滚动查找元素
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("查找的文本").instance(0));'
appium显式等待机制
wait等待方式
全局隐式等待
在服务端等待
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
显式等待
在客户端等待
new WebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated(By.xpath(“"))).action;
WebDriverWait用法
WebDriverWait 用法
wait=new WebDriverWait(driver, 10, 1000);
driver:浏览器驱动
timeOutInSeconds:最长超时时间,默认以秒为单位
sleepInMillis:检测的间隔步长,默认为0.5s
WebDriverWait 的 until()
wait.until(ExpectedConditions.visibilityOf(home_search)).click();
ExpectedConditions类
presenceOfElementLocated 判断元素是否被加到了DOM里,并不代表该元素一定见
用法:
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("home_search")));
visibilityOfElementLocated 判断某个元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0
用法
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(“home_search”));
显式等待案例
public void fun3(){
wait=new WebDriverWait(driver, 10, 1000);
driver.findElement(By.id("home_search")).click();
driver.findElement(By.id("search_input_text")).sendKeys("阿里巴巴");
wait=new WebDriverWait(driver, 10, 2);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@text='BABA']"))).click();
}
触屏操作自动化
TouchAction 用法
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/touch-actions.md
滑动
通过坐标滑动
touchAction.longPress(PointOption.point(200,600)).moveTo(PointOption.point(500,1200)).release().perform();
driver.manage().window().getSize().height
driver.manage().window().getSize().width
toast控件识别
案例
public void toastTest() throws Exception {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("udid", "emulator-5554");
caps.setCapability("deviceName", "xxxx");
caps.setCapability("appPackage", "io.appium.android.apis");
caps.setCapability("appActivity", "io.appium.android.apis.view.PopupMenu1");
caps.setCapability("noReset", "true");
driver = new AndroidDriver<>(new URL("http://localhost:4723/wd/hub"), caps);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.findElement(MobileBy.AccessibilityId("Make a Popup!")).click();
driver.findElement(By.xpath("//*[@text='Search']")).click();
System.out.println(driver.getPageSource());
System.out.println(driver.findElement(By.xpath("//*[@class='android.widget.Toast']")).getText());
}
appium属性获取与断言
Get_attribute原理分析
官方文档:
http://appium.io/docs/en/commands/element/attributes/attribute/
hamrest断言
官网:http://hamcrest.org/JavaHamcrest/
使用方法:
断言案例
public void priceTest() {
//定位首页搜索框
driver.findElement(By.id("com.xueqiu.android:id/home_search")).click();
//定位搜索页搜索框
driver.findElement(By.id("com.xueqiu.android:id/search_input_text")).sendKeys("阿里巴巴");
driver.findElement(By.xpath("//*[@text='BABA']")).click();
driver.findElement(By.xpath("//*[@resource-id='com.xueqiu.android:id/title_text'][@text='股票']")).click();
assertThat(Double.parseDouble(driver.findElement(
By.xpath("//*[@text='09988']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']")).getText())
,greaterThan(500d));
}
参数化案例
@ParameterizedTest
@MethodSource("byNameGetPrice")
public void comparePriceTest(String name,String code, double price) {
driver.findElement(By.id("com.xueqiu.android:id/home_search")).click();
//定位搜索页搜索框
driver.findElement(By.id("com.xueqiu.android:id/search_input_text")).sendKeys(name);
driver.findElement(By.xpath("//*[@text='"+code+"']")).click();
String stockPrice = driver.findElement(By.xpath("//*[@text='" + code + "']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']")).getText();
System.out.println(stockPrice);
driver.findElement(By.id("com.xueqiu.android:id/action_close")).click();
assertThat("股票的实际和预期价格对比",Double.parseDouble(stockPrice),greaterThan(price));
}
private static Stream<Arguments> byNameGetPrice() {
return Stream.of(
Arguments.of("alibaba", "BABA",210d),
Arguments.of("wangyi","NTES", 200d),
Arguments.of("baidu","BIDU", 185d),
Arguments.of("google","GOOGL", 300d)
);
}
Android 纯web页面测试
环境准备
手机端
被测浏览器:(不可以是第三方浏览器) ’Safari’ for iOS and ‘Chrome’, ‘Chromium’, or ‘Browser’ for Android,
PC端
安装Chrome浏览器(或chromium),并且能登录https://www.google.com/
下载对应手机浏览器对应的driver版本
国内镜像地址:CNPM Binaries Mirror
appium
github:https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md
客户端代码:
desirecapability
“browser” = “Browser” 或者“browser” = ”Chrome”
“chromedriverExecutable” = “指定driver地址”
Mac Chromedriver 默认地址:
/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/appium-chromedriver/chromedriver/mac/
获取webview版本
查看手机浏览器的版本
adb shell pm list package |grep webview
adb shell pm dump com.android.browser|grep version
adb shell pm dump com.android.chrome|grep version
adb shell pm dump com.android.webview|grep version
默认的浏览器启动
des_caps = {
'platformName': 'android',
'platformVersion': '6.0',
'browserName': 'Browser',
# 'browserName':'Chrome',
'deviceName':'192.168.56.101:5555',
# 'noReset': 'true'
}
self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", des_caps)
self.driver.get("http://m.baidu.com")
self.driver.implicitly_wait(5)
time.sleep(3)
appium混合应用
前提条件
PC:
浏览器能访问 https://www.google.com/
chromedriver下载对应的版本
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md
手机端
应用代码需要打开webview开关
代码
appPackage, appActivity
desirecapability里面添加:chromedriverExecutable:driver路径
webview开关
文档:
https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews?hl=zh-cn
定位元素方式
chrome://inspect
appium设备交互
常用的设备交互命令
官方地址:http://appium.io/docs/en/about-appium/intro/
模拟电话、短信
driver.makeGsmCall(PHONE_NUMBER, GsmCallActions.CALL);
driver.makeGsmCall(PHONE_NUMBER, GsmCallActions.ACCEPT);
driver.makeGsmCall(PHONE_NUMBER, GsmCallActions.CANCEL);
driver.sendSMS("555-123-4567", “Appium Test”);
网络设置
driver.toggleAirplaneMode();
driver.toggleWifi();
driver.toggleData();
横竖屏切换
切换成横屏
driver.rotate(Screenorientation.LANDSCAPE)
切换成竖屏
driver.rotate(Screenorientation.PORTRAIT)
其它常用操作
锁屏
driver.lock()
截图
File screenshotAs = driver.getScreenshotAs(OutputType.FILE);
File file=new File(System.getProperty(“user.dir")+"/src/main/resources/demo.png");
FileUtils.copyFile(screenshotAs,file);
录屏 模拟器需要androidAPI>27 ,华为不支持 只支持 8.0以上的版本
driver.startRecordingScreen();
driver.stopRecordingScreen();
设置地理位置 (only emulator)
driver.setLocation();
硬件操作
driver.pressKey(new KeyEvent().withKey(AndroidKey.BACK));
比如,back, home,menu,power, voice up,voice down,
keycode查看地址:
https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_MENU
Capability 高级用法
newCommandTimeout
udid
autoGrantPermissions
测试策略相关
- noReset
- fullreset
- dontStopAppOnReset
性能相关
- skipServerInstallation
- skipDeviceInitialization
- skipUnlock
- skipLogcatCapture
- systemPort
- relaxed-security 启动的时候设置
Appium 启动命令
Appium - relaxed-security
客户端测试平台
Android monkey测试工具
使用Monkey
adb shell monkey 100 对所有包随机操作
adb shell monkey -p com.xueqiu.android 100 对指定包
adb shell monkey -p com.xueqiu.android -s 20 80 时间种子
adb shell monkey -p com.xueqiu.android -vv -s 20 80 详细日志
时间延迟
adb shell monkey -p com.xueqiu.android --throttle 5000 100
事件百分比
adb shell monkey -p com.xueqiu.android --pct-touch 10 1000
常用事件
--pct-touch:触摸事件,比如点击
--pct-motion:动作事件,比如滑动(直线)
--pct-trackball:轨迹事件,比如移动+点击,曲线滑动
--pct-majornav:主要导航事件,比如回退按键、菜单按键:
maxim
使用
https://github.com/zhangzhao4444/Maxim
adb push framework.jar /sdcard
adb push monkey.jar /sdcard
命令
adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 60 -v -v
AppCrawler
项目地址:https://github.com/seveniruby/AppCrawler
环境要求
appcrawler 2.5
java8 appium 1.8.x
安装方法
- 直接下载
- 从源代码编译
备注
后面提到的appcrawler命令或者java -jar appcrawler.jar皆表示用jar -jar命令执行对应版本的jar包文件,比如
java -jar appcrawler-2.4.0-jar-with-dependencies.jar
quick_start
appcrawler --capability
“appPackage=com.xueqiu.android,appActivity=.view.WelcomeActivityAlias”
常用事件
参数模式
- java -jar <appcrawler.jar路径> --demo
- appcrawler --capability “appPackage=com.xueqiu.android,appActivity=.view.WelcomeActivityAlias”
配置文件 [推荐方式]
- java -jar <appcrawler.jar路径> \
- -c example.yml \
- –capability “appPackage=com.xueqiu.android,appActivity=.view.WelcomeActivityAlias” \
- -o /tmp/xueqiu/1
capability设置示例
appPackage: “com.xueqiu.android”
appActivity: “.view.WelcomeActivityAlias”
app:
appium: “http://127.0.0.1:4723/wd/hub”
noReset: true
automationName: uiautomator2
dontStopAppOnReset: true
OpenSTF
官网地址:https://github.com/openstf/stf
docker安装
docker pull openstf/stf:latest
docker pull sorccu/adb:latest
docker pull rethinkdb:latest
启动rethinkdb
docker run -d --name rethinkdb -v /srv/rethinkdb:/data --net host rethinkdb rethinkdb --bind all --cache-size 8192 --http-port 8090
启动stf
docker run -d --name stf --net host openstf/stf stf local --allow-remote
启动rethinkdb
docker run -d --name rethinkdb -v /srv/rethinkdb:/data --net host rethinkdb rethinkdb --bind all --cache-size 8192 --http-port 8090
localhost:7100
命令行启动
docker run --name=hub -p 5001:4444 -e GRID_TIMEOUT=0 -e GRID_THROW_ON_CAPABILITY_NOT_PRESENT=true -e GRID_NEW_SESSION_WAIT_TIMEOUT=-1 -e GRID_BROWSER_TIMEOUT=15000 -e GRID_TIMEOUT=30000 -e GRID_CLEAN_UP_CYCLE=30000 -d selenium/hub:3.7.1-beryllium
docker run --name=chrome -p 5902:5900 -e NODE_MAX_INSTANCES=6 -e NODE_MAX_SESSION=6 -e NODE_REGISTER_CYCLE=5000 -e DBUS_SESSION_BUS_ADDRESS=/dev/null -v /dev/shm:/dev/shm --link hub -d selenium/node-chrome-debug:3.7.1-beryllium
Selenium Grid
官网:https://www.selenium.dev/downloads/
hub
java -jar selenium-server-standalone-3.141.59.jar -role hub
node
java -jar selenium-server-standalone-3.141.59.jar -role node -port 5677
配置文件启动Node
java -jar selenium-server-standalone.jar -role node -nodeConfig node1Config.json
https://www.selenium.dev/documentation/en/grid/setting_up_your_own_grid/
selenium实现
把hub与nodes,放入字典
hub_nodes = {
"http://127.0.0.1:4444/wd/hub": "chrome",
"http://127.0.0.1:5677/wd/hub": "firefox",
"http://127.0.0.1:5678/wd/hub": "internet explore"
}
for host, browser in hub_nodes.items():
capabilities = {'platform': 'ANY',
'browserName': '',
'version': '',
'javascriptEnable': True
}
driver = Remote(command_executor=host,
desired_capabilities=capabilities)
driver.get("https://home.testing-studio.com/")
app自动化测试平台实战 1
动作支持action
“” 只是截图记录
back 后退
backApp 回退到当前的app 默认等价于back行为 可定制
monkey 随机事件
xxx() 执行代码
- Thread.sleep(3000)
- driver.swipe(0.9, 0.5, 0.1, 0.5)
click
longTap
非以上所有行为是输入 xx ddd
获取dom结构
windows
adb shell “uiautomator dump && cat /sdcard/window_dump.xml” | clip
adb shell “uiautomator dump && cat /sdcard/window_dump.xml” > tmp.xml
Mac
adb shell "uiautomator dump && cat /sdcard/window_dump.xml" | pbcopy
客户端专项测试
启动性能分析
adb logcat
package=com.xueqiu.android
清理缓存数据:adb shell pm clear $package
停止进程:adb shell am force-stop $package
启动app:adb shell am start -S -W $package/.view.WelcomeActivityAlias
获取数据:adb logcat |grep -i displayed
startTime:记录刚准备调用startActivityAndWait()的时间点;
endTime:记录startActivityAndWait()函数调用返回的时间点
WaitTime:startActivityAndWait()调用耗时
- WaitTime = endTime - startTime
使用ffmpeg拆帧
adb shell am force-stop $package
adb shell screenrecord --bugreport --time-limit 30 /data/local/tmp/xueqiu.mp4 &
adb shell am start -S -W $package/.view.WelcomeActivityAlias
wait
adb pull /data/local/tmp/xueqiu.mp4 .
ffmpeg -i xueqiu.mp4 xueqiu.gif
ffmpeg -i xueqiu.mp4 -r 10 frames_%03d.jpg
H5性能分析
https://www.w3.org/TR/navigation-timing/
自动化获取性能指标
appium/selenium的ExecuteScript Api
注⼊js
return JSON.stringify(window.performance.timing)
JSON.stringify(window.performance.getEntriesByName (document.querySelector("img").src)[0], null, 2)
卡顿分析
systrace
sdk/platform-tools/systrace
帧分析:
adb -s devicesname shell dumpsys gfxinfo | less
系统资源分析
参考阅读:https://developer.android.com/topic/performance/rendering/inspect-gpu-rendering
耗电量测试
安装:
git clone https://github.com/google/battery-historian.git
cd battery-historian
go get -d -u github.com/google/battery-historian/...
go run setup.go
go run cmd/battery-historian/battery-historian.go
batterystats收集数据
1. 清理耗电量数据
adb shell dumpsys batterystats --reset
adb shell dumpsys batterystats --enable full-wake-history
2. 运行测试用例/手工操作
3. 收集数据
Android 7.0:adb bugreport bugreport.zip
Android6.0:adb bugreport > bugreport.txt
上传数据
打开localhost:9999,把zip或者txt数据上传
使用脚本
start=$(date +%s);
while true; do
cur=$(date +%s);
((cur-start>6)) && break;
adb shell input swipe 100 800 100 300;
sleep 1;
echo $((cur-start));
done
弱网测试
使用charles模拟弱网
服务端性能测试
jmeter安装
jmeter分布式
influxDB
InfluxDB 是一个用 Go 语言开发的开源分布式时序数据库。
新建容器网络:docker network create grafana
运行容器:docker run -d --name=influxdb --network grafana -p 8086:8086 -v ${PWD}/influxdb/:/var/lib/influxdb/ influxdb:1.7.10
创建数据库
第一种方式:curl -i -XPOST http://localhost:8086/query --data-urlencode “q=CREATE DATABASE jmeter”
第二种方式:docker exec -it influxdb influx,执行语句 create database jmeter;
简单使用
show databases;
use jmeter;
show measurements;
select * from jmeter limit 3;
性能监控体系
部署Prometheus
配置文件:https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus.yml
运行:docker run -d --name prometheus --network grafana -p 9090:9090 -v ${PWD}/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus:v2.16.0 --config.file=/etc/prometheus/prometheus.yml
部署node_exporter
下载地址: https://github.com/prometheus/node_exporter/releases
配置Grafana
配置 Prometheus 数据源
配置面板:https://grafana.com/grafana/dashboards/8919
Docker容器技术
docker file
常用指令
FROM:基础镜像,FROM 命令必须是 Dockerfile 的首个命令。
LABEL:为镜像生成元数据标签信息。
USER:指定运行容器时的用户名或 UID,后续 RUN 也会使用指定用户。
RUN:RUN 命令是 Dockerfile 执行命令的核心部分。它接受命令作为参数并用于创建镜像。每条 RUN 命令在当前基础镜像上执行,并且会提交一个新镜像层。
WORKDIR:设置 CMD 指明的命令的运行目录。为后续的 RUN、CMD、ENTRYPOINT、ADD 指令配置工作目录。
ENV:容器启动的环境变量。
ARG:构建环境的环境变量。
COPY:复制文件
CMD:容器运行时执行的默认命令。
ENTRYPOINT:指定容器的“入口”。
HEALTHCHECK:容器健康状态检查。
Jenkins持续集成
节点管理
Jenkins的任务可以分布在不同的节点上运行
节点上需要配置Java运行时环境 ,Java_Version > 1.5
节点支持 Windows, Linux, Mac
Jenkins运行的主机在逻辑上是 master 节点
Jenkins报警机制
Jenkins 模板配置
- $BUILD_STATUS – 构建结果
- $PROJECT_NAME – 构建脚本名称
- $BUILD_NUMBER – 构建脚本编号
- $JOB_DESCRIPTION – 构建项目描述
- $CAUSE – 脚本启动原因
- $BUILD_URL – 脚本构建详情URL地址
持续交付
Jenkins API 接口
远程调用Jenkins API启动任务
远程API服务地址:
http://106.53.223.46:8080/job/first_job/build
远程调用Jenkins API返回最新任务编号
远程API服务地址:
http://106.53.223.46:8080/job/first_job/lastBuild/buildNumber
远程调用Jenkins API查询任务状态
远程API服务地址:
http://106.53.223.46:8080/job/first_job//api/json
Jenkins file语法简介
Declarative pipeline 示例代码
stages{
stage('git pull souce code'){
steps{
echo "sync updated code"
git "https://github.com/princeqjzh/iPipeline.git"
}
}
}
post {
success {
echo 'goodbye pipeline success!'
sleep 2
}
always {
echo 'always say goodbye'
}
}
options {
timeout(time: 30, unit: 'SECONDS')
buildDiscarder(logRotator(numToKeepStr: '2'))
retry(5)
}
parameters {
string(name: 'PERSON', defaultValue: 'Jenkins', description: '输入的文本参数')
}
stages {
stage('Test Parameters'){
steps {
echo "Hello ${params.PERSON}"
}
}
}
流程控制之 – if/else
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
流程控制之 – try/catch
node{
echo "This is test stage which run on the slave agent."
try {
echo "This is in the try block."
}catch (exc) {
echo "Something failed, I'm in the catch block."
}finally {
echo "Finally, I'm in the finally block."
}
}
例子源码地址:
https://gitee.com/ytq12875/pipeline
测试平台开发
测试平台前端
vue.js 安装
-
CDN
-
NPM
通过webpack和CLI安装使用
安装node.js环境
https://nodejs.org/zh-cn/download/
组件库的使用
ElementUI
https://element.eleme.io/#/
BootstrapVue
https://bootstrap-vue.org/
Vuetify
https://vuetifyjs.com/zh-Hans/
axios
安装
$ npm install axios
VSCode插件
Vetur:VSCode支持VUE的工具,有语法高亮、格式化、错误检查、自动完成等功能。
JavaScript (ES6) code snippets:包含VSCode的ES6语法中的JavaScript代码段。
(推荐)Auto Close Tag:自动添加HTML/XML结束标签。
(推荐)Auto Rename Tag:自动重命名对应的HTML/XML标签。
Highlight Matching Tag:突出显示匹配的开始和结束标签。
测试平台后端
Jenkins调用
Jenkins调用-maven依赖
<dependency>
<groupId>com.offbytwo.jenkins</groupId>
<artifactId>jenkins-client</artifactId>
<version>0.3.8</version>
</dependency>
常用类-JenkinsHttpClient
- 封装了调用JenkinsAPI的底层方法。
- JenkinsHttpClient(URI uri, String username, String password)
- get(String path)
- getFile(URI path)
- post(String path, boolean crumbFlag)
- post(String path, D data, Class cls)
- post_xml(String path, String xml_data, boolean crumbFlag)
等等
常用类-JenkinsServer
- 封装了调用JenkinsAPI的语义级别的方法。
- JenkinsServer(JenkinsHttpConnection client)
- getJob(String jobName)
- createJob(String jobName, String jobXml, Boolean crumbFlag)
- updateJob(String jobName, String jobXml, boolean crumbFlag)
- getJobXml(String jobName)
- deleteJob(FolderJob folder, String jobName, boolean crumbFlag)
等等
常用类-Job
- Jenkins中job对应的实体类,有很多实用的语义级别的方法。
- Job(String name, String url)
- build(Job job)
- build(Job job, Map<String, String> params)
- getFileFromWorkspace(String fileName)
- setClient(JenkinsHttpConnection client)
springboot
-
使用IDE的插件进行快速创建
restful风格的接口实现方式
-
SpringBootApplication:springboot主类,用来加载springboot各种特性
-
RestController:Spring会转换返回值并自动将其写入HTTP响应
-
RequestMapping: 用于类和方法,在方法级别时,用于处理HTTP 的各种方法
-
RequestBody:将request body中的json/xml对象解析成该参数类型的Javabean对象
-
PathVariable:处理动态的 URI,URI 的值可以作为控制器中处理方法的参数
-
Post/Put/Get/DeleteMapping:在方法的级别上使用,在方法级别时,用于处理HTTP 的各种方法
-
RequestParam:处理get请求的参数
lombok使用
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
集成swagger-配置类
@Configuration
@EnableSwagger2
public class SwaggerConfig {
}
集成swagger-配置项
@Bean
public Docket docket() {
//header
//apiInfo
}
private ApiInfo apiInfo() {
}
常用配置介绍
server:
port: 8093
connection-timeout: 18000000
servlet
session:
timeout: 30m #30分钟,测试的话时间不能太短,否则不准。m(分钟),s(秒),h(小时),不写单位默认毫秒
spring:
application:
name: aitest
springboot多环境配置
<profiles>
<!--开发环境-->
<profile>
<id>dev</id>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
简单运行脚本
test_start_8097.sh
nohup java -Xms256m -Xmx512m -XX:PermSize=64m -XX:MaxPermSize=128m -server -Dserver.port=8012 -jar aitest-mini.jar 'aitest-mini' --spring.profiles.active=dev >>./test_info_8097.log 2>&1 &
- ps -ef | grep aitest-mini #查询已经存在的aitest-mini进程,进程号为10179
- kill -9 10179 # 停止该进程
- sh test_start_8099.sh #执行启动命令
- tail -f test_info_8099.log #实时查看服务输出日志
Cors跨域资源共享
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
数据持久化技术
mybatis配置
- springboot集成mybatis配置
- mybatis相关配置
- sql语句打印配置
@MapperScan(“com.hogwartstest.aitestmini.dao”)
tk.mybatis使用-mapper统一父类
mybatis的mapper的统一父类,用于简单sql语句的快速编码
public interface MySqlExtensionMapper<T> extends Mapper<T>, MySqlMapper<T>, IdsMapper<T> {
}
持久化常见注解
-
Table:表对应的实体类标识,name属性为表名
-
Id:主键标识
-
GeneratedValue(strategy = GenerationType.IDENTITY):配置主键为自增策略
-
Column:列名标识,当类属性与表字段不符时,用name属性标识表字段
-
Transient:标识此字段不进行持久化
mybatis常见特性
-
#{createUserId}
-
${createUserId}
-
concat(‘%’, #{params.caseSign}, ‘%’):MySQL函数,返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。