1、Java+Appium 环境
https://www.jianshu.com/p/1b959e0baae2
2、识别与操作控件元素
找到Sdk oolsin下的uiautomatorviewer.bat双击
点击第一个图标,识别文件属性
- driver.findElementBy?(属性).sendKeys("数据")
- driver.findElementBy?(属性).clear()
- driver.findElementBy?(属性).click()
- driver.findElementBy?(属性).getText()
3、使用 Java 语言编写测试脚本
public class Appium003 { //AppiumDriver含义,建立于Appium的连接 AppiumDriver driver; @Test public void f() { } @SuppressWarnings("rawtypes") @BeforeClass public void beforeClass() { //创建DesiredCapabilities对象 //指定测试设备信息 DesiredCapabilities devices = new DesiredCapabilities(); //使用的移动设备或模拟器的种类,如 iPhone Simulator,iPad Simulator,Android Emulator,Galaxy S4 等 devices.setCapability("deviceName", "emulator-5554"); // 指定使用哪个移动操作系统平台,如 iOS,Android 或 FirefoxOS devices.setCapability("platformName","Android"); //指定移动操作系统版本 devices.setCapability("platformVersion","11"); // 指定 app 程序包名,即被测程序名 devices.setCapability("appPackage","com.example.calculate"); devices.setCapability("appActivity","com.example.simplecalculate.MainActivity"); //A new session could not be created的解决方法 devices.setCapability("appWaitActivity","com.example.simplecalculate.MainActivity"); //每次启动时覆盖session,否则第二次后运行会报错不能新建session devices.setCapability("sessionOverride", true); //启动 App try { driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),devices); driver.findElementById("com.example.calculate:id/guide_button_close").click(); } catch (MalformedURLException e) { e.printStackTrace(); } } @AfterClass public void afterClass() { driver.quit(); } }
@Listeners({TestReport.class}) public class Appium0202 { //AppiumDriver含义,建立于Appium的连接 // AppiumDriver driver; AndroidDriver driver; @Test public void f() { /*** * 方式一,数字是一次一次点击的输入 * *****/ System.out.println("进入-----------------------------------"); driver.findElementById("android:id/button1").click(); driver.findElementById("com.android.calculator2:id/digit2").click(); driver.findElementById("com.android.calculator2:id/digit0").click(); driver.findElementById("com.android.calculator2:id/plus").click(); driver.findElementById("com.android.calculator2:id/digit2").click(); driver.findElementById("com.android.calculator2:id/digit0").click(); driver.findElementById("com.android.calculator2:id/equal").click(); String result=driver.findElementByClassName("android.widget.EditText").getText(); System.out.println(result); //断言 Boolean res=result.contains("40"); Assert.assertTrue(res); /**** * 方式二:数字采用循环输入的方式 * * ****/ //清除结果框里面的内容 driver.findElementByClassName("android.widget.EditText").clear(); String numberA = "234"; String numberB = "432"; String plus = "plus"; String equal = "equal"; for(int i=0;i<numberA.length();i++) { driver.findElementById("com.android.calculator2:id/digit"+numberA.charAt(i)).click(); } driver.findElementById("com.android.calculator2:id/"+plus).click(); for(int i=0;i<numberB.length();i++) { driver.findElementById("com.android.calculator2:id/digit"+numberB.charAt(i)).click(); } driver.findElementById("com.android.calculator2:id/"+equal).click(); result=driver.findElementByClassName("android.widget.EditText").getText(); System.out.println("第二次的结果=="+result); Assert.assertEquals(result, "666"); /*** * 方法三:利用数组的方式,设计用例,详情见 Appium0203 * ***/ } @BeforeClass public void beforeClass() { //创建DesiredCapabilities对象 //指定测试设备信息 DesiredCapabilities devices = new DesiredCapabilities(); //使用的移动设备或模拟器的种类,如 iPhone Simulator,iPad Simulator,Android Emulator,Galaxy S4 等 devices.setCapability("deviceName", "emulator-5554"); // 指定使用哪个移动操作系统平台,如 iOS,Android 或 FirefoxOS devices.setCapability("platformName","Android"); //指定移动操作系统版本 devices.setCapability("platformVersion","11"); // 指定 app 程序包名,即被测程序名 devices.setCapability("appPackage","com.android.calculator2"); devices.setCapability("appActivity","com.android.calculator2.Calculator"); //A new session could not be created的解决方法 devices.setCapability("appWaitActivity","com.android.calculator2.Calculator"); //每次启动时覆盖session,否则第二次后运行会报错不能新建session devices.setCapability("sessionOverride", true); //启动 App try { driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),devices); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @AfterClass public void afterClass() { driver.quit(); } }
方法三:利用数组的方式,设计用例
public class Appium0203 { AndroidDriver driver; @Test(dataProvider = "getData") public void f(String number01,String operator,String number02,String expected) { /*** * 方法三:利用数组的方式,设计用例 * ***/ System.out.println("进入-----------------------------------"); //数字一 for(int i=0;i<number01.length();i++) { driver.findElementById("com.android.calculator2:id/digit"+number01.charAt(i)).click(); } //运算符号 String hao=""; switch (operator) { case "+": hao="plus"; break; case "-": hao="minus"; break; case "*": hao="mul"; break; case "/": hao="div"; break; default: hao="plus"; break; } driver.findElementById("com.android.calculator2:id/"+hao).click(); //数字二 for(int i=0;i<number02.length();i++) { driver.findElementById("com.android.calculator2:id/digit"+number02.charAt(i)).click(); } //点击= driver.findElementById("com.android.calculator2:id/equal").click(); String result = driver.findElementByClassName("android.widget.EditText").getText(); Assert.assertEquals(result, expected); //输出结果 System.out.println("结果=="+result); //driver.findElementById("com.android.calculator2:id/del").click(); } @DataProvider public Object[][] getData(){ Object data[][] = {{"234","+","432","666"},{"999","-","333","666"},{"2","*","88","176"}}; return data; } @BeforeClass public void beforeClass() { //创建DesiredCapabilities对象 //指定测试设备信息 DesiredCapabilities devices = new DesiredCapabilities(); //使用的移动设备或模拟器的种类,如 iPhone Simulator,iPad Simulator,Android Emulator,Galaxy S4 等 devices.setCapability("deviceName", "emulator-5554"); // 指定使用哪个移动操作系统平台,如 iOS,Android 或 FirefoxOS devices.setCapability("platformName","Android"); //指定移动操作系统版本 devices.setCapability("platformVersion","11"); // 指定 app 程序包名,即被测程序名 devices.setCapability("appPackage","com.android.calculator2"); devices.setCapability("appActivity","com.android.calculator2.Calculator"); //A new session could not be created的解决方法 devices.setCapability("appWaitActivity","com.android.calculator2.Calculator"); //每次启动时覆盖session,否则第二次后运行会报错不能新建session devices.setCapability("sessionOverride", true); //启动 App try { driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),devices); driver.findElementById("android:id/button1").click(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @AfterClass public void afterClass() { driver.quit(); } }
方法四:读取外部文件中的测试数据
@Listeners({TestReport.class}) public class Appium0204 { //AppiumDriver含义,建立于Appium的连接 // AppiumDriver driver; AndroidDriver driver; @Test(dataProvider = "getData") public void f(String number01,String operator,String number02,String expected) { /*** * 方法四:读取外部文件中的测试数据 * ***/ System.out.println("进入-----------------------------------"); //数字一 for(int i=0;i<number01.length();i++) { driver.findElementById("com.android.calculator2:id/digit"+number01.charAt(i)).click(); } //运算符号 String hao=""; switch (operator) { case "+": hao="plus"; break; case "-": hao="minus"; break; case "*": hao="mul"; break; case "/": hao="div"; break; default: hao="plus"; break; } driver.findElementById("com.android.calculator2:id/"+hao).click(); //数字二 for(int i=0;i<number02.length();i++) { driver.findElementById("com.android.calculator2:id/digit"+number02.charAt(i)).click(); } //点击= driver.findElementById("com.android.calculator2:id/equal").click(); String result = driver.findElementByClassName("android.widget.EditText").getText(); Assert.assertEquals(result, expected); //输出结果 System.out.println("结果=="+result); } @DataProvider public Object[][] getData() throws Exception{ List<String[]> rows = new ArrayList<String[]>(); //读取文件数据 File file = new File("e:\calc.txt"); FileReader bytes = new FileReader(file); BufferedReader chars = new BufferedReader(bytes); String row = null; while((row = chars.readLine())!=null) { String cols[] = row.split(" "); rows.add(cols); } bytes.close(); Object[][] data = new Object[rows.size()][]; for(int i=0;i<rows.size();i++) { data[i] = rows.get(i); } return data; } @BeforeClass public void beforeClass() { //创建DesiredCapabilities对象 //指定测试设备信息 DesiredCapabilities devices = new DesiredCapabilities(); //使用的移动设备或模拟器的种类,如 iPhone Simulator,iPad Simulator,Android Emulator,Galaxy S4 等 devices.setCapability("deviceName", "emulator-5554"); // 指定使用哪个移动操作系统平台,如 iOS,Android 或 FirefoxOS devices.setCapability("platformName","Android"); //指定移动操作系统版本 devices.setCapability("platformVersion","11"); // 指定 app 程序包名,即被测程序名 devices.setCapability("appPackage","com.android.calculator2"); devices.setCapability("appActivity","com.android.calculator2.Calculator"); //A new session could not be created的解决方法 devices.setCapability("appWaitActivity","com.android.calculator2.Calculator"); //每次启动时覆盖session,否则第二次后运行会报错不能新建session devices.setCapability("sessionOverride", true); //启动 App try { driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),devices); driver.findElementById("android:id/button1").click(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @AfterClass public void afterClass() { driver.quit(); } }
输出测试报告
测试报告默认存储位置: Java 项目名 est-output
测试类中添加监听器@Listeners({TestReport.class})即可
如
@Listeners({TestReport.class}) public class Appium0204 {
TestReport.java
package com01; //修改为正确的包名 import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.TestListenerAdapter; public class TestReport extends TestListenerAdapter{ private String reportPath; @Override public void onStart(ITestContext context) { File htmlReportDir = new File("test-output"); if (!htmlReportDir.exists()) { htmlReportDir.mkdirs(); } String reportName = formateDate()+"_result.html"; reportPath = htmlReportDir+"/"+reportName; File report = new File(htmlReportDir,reportName); if(report.exists()){ try { report.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } StringBuilder sb = new StringBuilder("<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />" + "<title>自动化测试报告</title></head><body style="background-color:#99FFCC;">" + "<div id="top" align="center"><p style="font-weight:bold;">测试用例运行结果列表</p>" + "<table width="90%" height="80" border="1" align="center" cellspacing="0" rules="all" style="table-layout:relative;">" + "<thead>" + "<tr>" + "<th>测试用例名</th>" + "<th>测试用例结果</th>" + "</tr>" + "</thead>" + "<tbody style="word-wrap:break-word;font-weight:bold;" align="center">"); String res = sb.toString(); try { Files.write((Paths.get(reportPath)),res.getBytes("utf-8")); } catch (IOException e) { e.printStackTrace(); } } @Override public void onTestSuccess(ITestResult result) { StringBuilder sb = new StringBuilder("<tr><td>"); sb.append(result.getMethod().getRealClass()+"."+result.getMethod().getMethodName()); sb.append("</td><td><font color="green">Passed</font></td></tr>"); String res = sb.toString(); try { Files.write((Paths.get(reportPath)),res.getBytes("utf-8"),StandardOpenOption.APPEND); } catch (IOException e) { e.printStackTrace(); } } @Override public void onTestSkipped(ITestResult result) { StringBuilder sb = new StringBuilder("<tr><td>"); sb.append(result.getMethod().getRealClass()+"."+result.getMethod().getMethodName()); sb.append("</td><td><font color="yellow">Skipped</font>"); sb.append("<p align="left">测试用例<font color="red">跳过</font>,原因:<br>"); sb.append("<br><a style="background-color:#CCCCCC;">"); Throwable throwable = result.getThrowable(); sb.append(throwable.getMessage()); sb.append("</a></p></td></tr>"); String res = sb.toString(); try { Files.write((Paths.get(reportPath)),res.getBytes("utf-8"),StandardOpenOption.APPEND); } catch (IOException e) { e.printStackTrace(); } } @Override public void onTestFailure(ITestResult result) { StringBuilder sb = new StringBuilder("<tr><td>"); sb.append(result.getMethod().getRealClass()+"."+result.getMethod().getMethodName()); sb.append("</td><td><font color="red">Failed</font><br>"); sb.append("<p align="left">测试用例执行<font color="red">失败</font>,原因:<br>"); sb.append("<br><a style="background-color:#CCCCCC;">"); Throwable throwable = result.getThrowable(); sb.append(throwable.getMessage()); sb.append("</a></p></td></tr>"); String res = sb.toString(); try { Files.write((Paths.get(reportPath)),res.getBytes("utf-8"),StandardOpenOption.APPEND); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFinish(ITestContext testContext) { StringBuilder sb = new StringBuilder("</tbody></table><a href="#top">返回顶部</a></div></body>"); sb.append("</html>"); String msg = sb.toString(); try { Files.write((Paths.get(reportPath)),msg.getBytes("utf-8"),StandardOpenOption.APPEND); } catch (IOException e) { e.printStackTrace(); } } public static String formateDate(){ SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd HHmmss"); Calendar cal = Calendar.getInstance(); Date date = cal.getTime(); return sf.format(date); } }
断言
1 、Assert.assertTrue(boolean型结果)
Ø 写法类似于正则表达式,使用更方便。
Ø Boolean rs=driver.findElementById(…).getText().contains();
Ø Assert.assertTrue(rs);
2、 Assert.assertEquals(实际结果,预期结果)
Ø 用于测试期望结果的断言,即测试两个对象是否相等。
Ø Stringactual=实际结果;
Ø Stringexpected=预期结果;
Ø Assert.assertEquals(actual, expected);
ü Stringres=driver.findElementByClassName("android.widget.EditText").getText();
ü Assert.assertEquals(res,"3");
模拟按键
8 模拟按键 driver.pressKeyCode(keycode) 必须使用 AmdroidDriver 基本 KEYCODE_0 按键'0' 7 KEYCODE_1 按键'1' 8 KEYCODE_2 按键'2' 9 KEYCODE_3 按键'3' 10 KEYCODE_4 按键'4' 11 KEYCODE_5 按键'5' 12 KEYCODE_6 按键'6' 13 KEYCODE_7 按键'7' 14 KEYCODE_8 按键'8' 15 KEYCODE_9 按键'9' 16 KEYCODE_A 按键'A' 29 KEYCODE_B 按键'B' 30 KEYCODE_C 按键'C' 31 KEYCODE_D 按键'D' 32 KEYCODE_E 按键'E' 33 KEYCODE_F 按键'F' 34 KEYCODE_G 按键'G' 35 KEYCODE_H 按键'H' 36 KEYCODE_I 按键'I' 37 KEYCODE_J 按键'J' 38 KEYCODE_K 按键'K' 39 KEYCODE_L 按键'L' 40 KEYCODE_M 按键'M' 41 KEYCODE_N 按键'N' 42 KEYCODE_O 按键'O' 43 KEYCODE_P 按键'P' 44 KEYCODE_Q 按键'Q' 45 KEYCODE_R 按键'R' 46 KEYCODE_S 按键'S' 47 KEYCODE_T 按键'T' 48 KEYCODE_U 按键'U' 49 KEYCODE_V 按键'V' 50 KEYCODE_W 按键'W' 51 KEYCODE_X 按键'X' 52 KEYCODE_Y 按键'Y' 53 KEYCODE_Z 按键'Z' 54 功能键 KEYCODE_CALL 拨号键 5 KEYCODE_ENDCALL 挂机键 6 KEYCODE_HOME 按键 Home 3 KEYCODE_MENU 菜单键 82 KEYCODE_BACK 返回键 4 KEYCODE_SEARCH 搜索键 84 KEYCODE_CAMERA 拍照键 27 KEYCODE_FOCUS 拍照对焦键 80 KEYCODE_POWER 电源键 26 KEYCODE_NOTIFICATION 通知键 83 KEYCODE_MUTE 话筒静音键 91 KEYCODE_VOLUME_MUTE 扬声器静音键 164 KEYCODE_VOLUME_UP 音量增加键 24 KEYCODE_VOLUME_DOWN 音量减小键 25 控制键 KEYCODE_ENTER 回车键 66 KEYCODE_ESCAPE ESC 键 111 KEYCODE_DPAD_CENTER 导航键 确定键 23 KEYCODE_DPAD_UP 导航键 向上 19 KEYCODE_DPAD_DOWN 导航键 向下 20 KEYCODE_DPAD_LEFT 导航键 向左 21 KEYCODE_DPAD_RIGHT 导航键 向右 22 KEYCODE_MOVE_HOME 光标移动到开始键 122 KEYCODE_MOVE_END 光标移动到末尾键 123 KEYCODE_PAGE_UP 向上翻页键 92 KEYCODE_PAGE_DOWN 向下翻页键 93 KEYCODE_DEL 退格键 67 KEYCODE_FORWARD_DEL 删除键 112 KEYCODE_INSERT 插入键 124 KEYCODE_TAB Tab 键 61 KEYCODE_NUM_LOCK 小键盘锁 143 KEYCODE_CAPS_LOCK 大写锁定键 115 KEYCODE_BREAK Break/Pause 键 121 KEYCODE_SCROLL_LOCK 滚动锁定键 116 KEYCODE_ZOOM_IN 放大键 168 KEYCODE_ZOOM_OUT 缩小键 169 组合键 KEYCODE_ALT_LEFT Alt+Left KEYCODE_ALT_RIGHT Alt+Right KEYCODE_CTRL_LEFT Control+Left KEYCODE_CTRL_RIGHT Control+Right KEYCODE_SHIFT_LEFT Shift+Left KEYCODE_SHIFT_RIGHT Shift+Right