1、Java+Appium 環境
https://www.jianshu.com/p/1b959e0baae2
2、識別與操作控件元素
找到\Sdk\tools\bin下的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("\t"); 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 項目名\test-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