人类历史上第一篇小程序测试布道贴 使用 appium 进行微信小程序的自动化测试推出至今,已有近两年时间了。而我们才刚刚研究小程序测试,谁知道刚还没入门,就从踏坑开始了,也怪我为了兼容 IOS 测试,升级了 Java-Client.jar。17 年至今 Appium,Java-Client 也发行好几个版本了,肯定有不少人升级了 Java-Client.jar 到 6+,升级后应该会遇到小程序测试时报异常。Python,和使用 Java-Client5 没有问题。Log 我就不贴了,不服升级一下 Appium 和 Java-Client 到最新版试试。
发生异常后,分别使用 Python 和 Java 用不同的版本做了测试分析。发现 Py 一直是可以的,用最新的 pyClient,和上一个版本都没有问题的。Java 的 Client 升级到 5.0.4 后就开始报错了。明明代码里没有设置 browserName 选项,但是程序运行时,会自动化启动谷歌浏览器,然后小程序测试就异常了。以下是 Java Client 不同版本的调查结果。
Java Client 5.0.0 --> selenium-java 3.5.2 --> OK
Java Client 5.0.1 --> selenium-java 3.5.2 --> OK
Java Client 5.0.2 --> selenium-java 3.5.3 --> OK
Java Client 5.0.3 --> selenium-java 3.5.3 --> OK
Java Client 5.0.4 --> selenium-java 3.6.0 --> Error
Java Client 6.0.0 --> selenium-java 3.12.0 --> Error
经过调查,确定以及肯定不是我代码程序的问题,因为同样的设置 Py 和低版本的 Java-Client 都可以正常运行。只好跑去用撇脚的英语给 Appium 提 ISSUE 了 。
不得不说 Appium 的团队还是很热心的,提供 log 后,很快得到了回应。非常感谢他们开源贡献!
Appium 的大神说这是 Selenium 的锅。已经有小伙伴去给 SeleniumHQ 提 Issue 了。不知道 SeleniumHQ 会不会认领这个锅,也不知道这个问题改正还需要多久。这里把大神给的方案贴一下,传递开源精神。
环境:
1.Java-client : 6.1.0
2.Android System WebView : 57.0
3.chromedriver : 2.29
4.Appium server:1.8.1
5.Mobile : Android 6.0
package com.lvmama.testcase;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
public class WeXinTest {
static AndroidDriver<MobileElement> driver = null;
public static void main(String[] args) throws Exception {
DesiredCapabilities desired_capabilities = new DesiredCapabilities();
ChromeOptions chrome_options = new ChromeOptions();
chrome_options.setExperimentalOption("androidProcess", "com.tencent.mm:tools");
desired_capabilities.setCapability(ChromeOptions.CAPABILITY, chrome_options);
desired_capabilities.setCapability(AndroidMobileCapabilityType.PLATFORM, "Android");
desired_capabilities.setCapability(AndroidMobileCapabilityType.VERSION, "6.0");
desired_capabilities.setCapability("deviceName", "a6990c40");
desired_capabilities.setCapability(MobileCapabilityType.FORCE_MJSONWP, true);
desired_capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.tencent.mm");
desired_capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "ui.LauncherUI");
desired_capabilities.setCapability("showChromedriverLog", true);
desired_capabilities.setCapability(AndroidMobileCapabilityType.AUTO_GRANT_PERMISSIONS, true);
desired_capabilities.setCapability("noReset", true);
desired_capabilities.setCapability(MobileCapabilityType.BROWSER_NAME,"");
desired_capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "uiautomator2");
try {
driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"),desired_capabilities);
Thread.sleep(2000);
driver.findElementByXPath("//*[@text='发现']").click();
Thread.sleep(2000);
driver.findElementByXPath("//*[@text='小程序']").click();
Thread.sleep(2000);
driver.findElementByXPath("//*[@text='驴妈妈门票预订']").click();
Thread.sleep(5000);
Set<String> contextNames = driver.getContextHandles();
for(String contextName : contextNames) {
lvmama:if(contextName.contains("tencent.mm:appbrand0")){
driver.context(contextName);
Set<String> winHandles = driver.getWindowHandles();
for(String wid : winHandles) {
driver.switchTo().window(wid);
String source = driver.getPageSource();
if (source.contains("票")) {//好粗暴
break lvmama;
}
}
}
}
Thread.sleep(5000);
System.out.println(driver.getPageSource());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
ChromeOptions 的设置:chrome_options.setExperimentalOption("androidProcess", "com.tencent.mm:tools");
这个"com.tencent.mm:tools"可以是 “com.tencent.mm:appbrand0” 但是设置成 “com.tencent.mm:appbrand1” 就不一定对了。
设置时一定要看 Webview 的进程名,这个蛋疼的 appbrandX 的 X 是会变的,切莫生搬套用。
当前 Webview 的进程名查看方法,详尽方法参考这个 使用 Appium 测试微信小程序 Webview
进入小程序页面时要切上下文,老规矩看上一步,查清楚自己 Webview 的进程名
if(contextName.contains("tencent.mm:appbrandX")){//appbrand0,appbrand1,appbrand2。。。都有可能。
driver.context(contextName);
}
切完上下文,注意要切换 WindowHandle,判断确实是自己的页面再退出循环。(我这个判断是否进入自己页面用的是 getPageSource() 有点挫,不知道大家有啥好方法,欢迎留言讨论,谢谢)
Set<String> winHandles = driver.getWindowHandles();
for(String wid : winHandles) {
driver.switchTo().window(wid);
String source = driver.getPageSource();
if (source.contains("票")) {
break;
}
}
现在各大门派都要搞小程序(BAT T..),我这还没入门就入坑了,大家有啥好方案,欢迎留言不吝赐教。最后感谢社区很多优秀的帖子给予参考,感谢 Appium 调查解决。