跳到正文
W Winse Blog
mobile dev windows automation 4 min read

appium-Android自动化测试

# 参考链接

# 步骤

# 手机端开发这模式需要进行如下设置:

  • (可选)不锁定屏幕
  • USB调试
  • USB安装
  • USB调试(安全设置)

# 安装启动Appium Desktop

  1. 点击编辑配置

设置ANDROID_HOME C:\Android\Sdk

  1. 启动服务

  2. 使用/应用

按步骤操作,先用[检查器会话]的执行一次。这里会给手机安装两个应用,最开始开发者模式的设置就是为安装应用来修改的。

3.1 启动检查器会话

启动服务后,会进入到黑窗口日志界面。点击界面右上角第一个放大镜按钮:[启动检查器会话],编辑[所需功能]

{
  "platformName": "Android",
  "platformVersion": "7.1",
  "appPackage": "com.miui.calculator",
  "appActivity": ".cal.CalculatorActivity"
}

如果不需要录制脚本,可以使用 C:\Android\Sdk\tools\bin\uiautomatorviewer.bat 查看也可以的。

3.2 Java客户端

	public static final String APP_ID = "com.taobao.idlefish";

	private static AppiumDriverLocalService service;

	private static AndroidDriver<AndroidElement> driver;
	private static WebDriverWait wait;

	private void initialization() throws MalformedURLException {
		initialization(APP_ID, "com.taobao.idlefish.router.JumpActivity", true, false);
	}

	private void initialization1() throws MalformedURLException {
		initialization("com.miui.calculator", ".cal.CalculatorActivity", null, null);
	}

	/**
	 * @param noReset    null will remove from the caps.
	 * @param autoLaunch null will remove from the caps.
	 */
	protected void initialization(String appPackage, String appActivity, Boolean noReset, Boolean autoLaunch) throws MalformedURLException {
		URL url = new URL("http://localhost:4723/wd/hub");

		DesiredCapabilities capabilities = new DesiredCapabilities();
		capabilities.setCapability("automationName", "UiAutomator2" /* "Appium" */);
		capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
		capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");

		capabilities.setCapability("appPackage", appPackage);
		capabilities.setCapability("appActivity", appActivity);
		// http://appium.io/docs/en/writing-running-appium/caps/
		capabilities.setCapability("noReset", noReset);
		capabilities.setCapability("autoLaunch", autoLaunch);
		
		capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 100);

		driver = new AndroidDriver<>(url, capabilities);
		wait = new WebDriverWait(driver, 20);
	}
	
	protected void finishing() {
		try {
			if (driver != null) {
				driver.quit();
			}
			if (service != null) {
				service.stop();
			}
		} catch (Exception e) {
		} finally {
			driver = null;
			service = null;
		}
	}

	protected void swiping() {
		Dimension windowSize = getSize();

		int startX = windowSize.width / 2;
		int startY = (int) (windowSize.height * 0.8);
		int endX = windowSize.width / 2;
		int endY = (int) (windowSize.height * 0.1);

		swipe(startX, startY, endX, endY, 1200);
	}
	
	protected void swipe(int x1, int y1, int x2, int y2, int waitMillis) {
		new TouchAction<>(driver) //
				.press(ElementOption.point(x1, y1))
				.waitAction(WaitOptions.waitOptions(Duration.ofMillis(waitMillis)))
				.moveTo(ElementOption.point(x2, y2))
				.release()
				.perform();
	}
	
	protected void touch(int x, int y) {
		new TouchAction<>(driver).tap(TapOptions.tapOptions().withPosition(PointOption.point(x, y))).perform();
	}
	
	protected void touch(Point p) {
		touch(p.x, p.y);
	}
	
	protected Dimension getSize() {
		return driver.manage().window().getSize();
	}

	protected Point getCenter() {
		Dimension size = getSize();
		return new Point(size.width / 2, size.height / 2);
	}
	
	private void touchAndWait() throws InterruptedException {
		touchAndWait(null);
	}

	private void touchAndWait(By by) throws InterruptedException {
		// 等一下界面效果
//		Thread.sleep(500);
		TimeUnit.MILLISECONDS.sleep(500);

		try {
			swiping();
		} catch (Exception e) {
			touch(getCenter());
		}

		if (by != null) {
			wait.until(ExpectedConditions.presenceOfElementLocated(by));
		}
	}

	private void doCalculator() throws InterruptedException {
		By btn_9_s = By.id("com.miui.calculator:id/btn_9_s");
		By btn_plus_s = By.id("com.miui.calculator:id/btn_plus_s");
		By btn_3_s = By.id("com.miui.calculator:id/btn_3_s");
		By btn_equal_s = By.id("com.miui.calculator:id/btn_equal_s");
		By textViews = By.className("android.widget.TextView");

		touchAndWait(btn_9_s);
		driver.findElement(btn_9_s).click();
		// driver.findElementByAccessibilityId("加");
		driver.findElement(btn_plus_s).click();
		driver.findElement(btn_3_s).click();
		driver.findElement(btn_equal_s).click();

		touchAndWait(textViews);
		List<? extends WebElement> allText = driver.findElements(textViews);
		boolean isOk = false;
		for (int i = 0; i < allText.size(); i++) {
			String txt = allText.get(i).getText();
			System.out.println(txt);

			// 由于第一次无法根据元素的ClassName确定顺序,所以使用遍历的方式进行断言
			if (txt.equals("= 12")) {
				isOk = true;
				break;
			}
		}

		if (isOk) {
			System.out.println("测试成功.");
		} else {
			System.out.println("测试失败.");
		}
	}

	public void testCalculator() throws Exception {
		try {
			initialization1();

			doCalculator();
		} finally {
			finishing();
		}
	}
	
	public void testHello() throws InterruptedException, MalformedURLException {
		try {
			this.initialization1();

			doCalculator();

			driver.activateApp(APP_ID);
//	        driver.startActivity(new Activity(APP_ID, "com.taobao.idlefish.router.JumpActivity"));

			test0();
			test1();
		} finally {
			this.finishing();
		}
	}
	
	private String toString(Rectangle rect) {
		return String.format("(%s,%s,%s,%s)", rect.x, rect.y, rect.width, rect.height);
	}
	
	private void printAllView() throws Exception {
		try {
			List<AndroidElement> allText = driver.findElementsByXPath("//*");
			for (int i = 0; i < allText.size(); i++) {
				AndroidElement ele = allText.get(i);
				
				System.out.println("===========================");
				System.out.println(ele.getTagName() + ","
						+ ele.isSelected() + "," 
						+ ele.isEnabled() + "," 
						+ ele.isDisplayed() + "," 
						+ ele.getText() + "," 
						+ toString(ele.getRect()));
				
				System.out.println(ele.getAttribute("class"));
				System.out.println(ele.getAttribute("content-desc"));
				System.out.println(ele.getAttribute("text"));
			}
			
		} catch (Exception e) {
			String errMsg = e.getMessage();
			System.err.println(errMsg);

			if (errMsg.contains("A session is either terminated or not started")) {
				try {
					this.finishing();
				} catch (Exception ex) {
				}

				this.initialization();
			}
		}
	}

	private void doProcessManual() throws Exception {
		while (true) {
			printAllView();

			swiping();

			Thread.sleep(1000);
		}
	}

	public void testXianyu() throws Exception {
		try {
			this.initialization();

			doProcessManual();
		} finally {
			this.finishing();
		}
	}

	private void test0() {
		System.out.println("appId: " + driver.getCurrentPackage());
		System.out.println("activity: " + driver.currentActivity());
		
		System.out.println(APP_ID + " installed?: " + driver.isAppInstalled(APP_ID));

//        driver.runAppInBackground(Duration.ofSeconds(-1));
//        driver.activateApp(appId);
//        driver.closeApp();
//        driver.resetApp();
//        driver.rotate(new DeviceRotation(0, 0, 0));
//        driver.launchApp();
	}

	private void test1() {
		System.out.println("AppStringMap size: " + driver.getAppStringMap().size());
		System.out.println("en AppStringMap size: " + driver.getAppStringMap("en").size());
		
		System.out.println("build: " + driver.getStatus().get("build"));
		
		System.out.println("DeviceTime: " + driver.getDeviceTime());
	}

–END

在 GitHub 上讨论

欢迎通过 GitHub Issue 留言或反馈。每条讨论都会关联到对应文章的源文件路径。

src/posts/2020-04-12-appium-android-auto-test.md

Related posts