WebView 自动化测试
webview 自动化测试方法
| 方式 | 技术栈 | 优点 | 缺点 |
|---|---|---|---|
| 原生自动化 | uiautomator appium atx |
简单 不依赖 webview 调试开关开启 |
不易维护 |
| web 自动化 | selenium chromedriver minitest |
易维护 | 不适合混合开发 依赖 webview 调试开关开启 |
| 混合自动化 | appium | 易维护,通用 | 技术复杂 依赖 webview 调试开关开启 |
混合自动化技术原理
- 使用多引擎管理自动化,维持一套 driver 两套 session 机制
- 使用 chromedriver 自动化 webview 组件
- 使用 native 方式自动化 native 控件


appium webview 自动化测试前提
- chromedriver 安装
- chromedriver 版本选择正确
- appium capability 参数配置
chromedriver 安装
- 如果未安装 chromedriver 会报错
- 国内 chromedriver 下载地址
No Chromedriver found that can automate Chrome 'x.x.xxxx'. You could also try to enable automated chromedrivers download server feature. See ... for more details
chromedriver 版本选择
- chromedriver 版本与 chrome webview 版本存在绑定关系
- appium 有版本判断,版本不对会出错
- app 内置 webview 组件可能会跟系统默认自带的 webview 组件不一致,以 app 使用的 webview 为准
unknown error: Chrome version must be >= xx.x.x.xxxx
appium chromedriver 自动发现机制
- chromedriverExecutableDir 指定 chromedriver 可执行文件集合的目录
- chromedriverChromeMappingFile 允许显式指定版本对应关系
- showChromedriverLog 让 appium 日志展示 chromedriver 的日志方便排查
设置 capability 示例 -- python
def setup(self):
caps = {
"platformName": "android",
"deviceName": "hogwarts",
"appPackage": "com.xueqiu.android",
"appActivity": ".view.WelcomeActivityAlias",
"chromedriverExecutableDir": "/Users/seveniruby/projects/chromedriver/chromedrivers",
"chromedriverChromeMappingFile": "/Users/seveniruby/PycharmProjects/LagouTesting/test_app/chromedriver.json",
# "chromedriverExecutable": "/Users/seveniruby/projects/chromedriver/chromedrivers/chromedriver_2.20",
"autoGrantPermissions": "true"
}
self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
self.driver.implicitly_wait(10)
设置 capability 示例 -- java
//简单的方案
caps.setCapability("chromedriverExecutable", "/Users/seveniruby/projects/chromedriver/72/chromedriver");
//完善的自动发现方案
caps.setCapability("chromedriverExecutableDir", "/Users/seveniruby/projects/chromedriver/2.20");
caps.setCapability("chromedriverChromeMappingFile", "/Users/seveniruby/projects/Java3/src/test/java/test_app/wechat/mapping.json");
caps.setCapability("showChromedriverLog", true);
appium context 上下文机制
- 展示所有的上下文 contexts 第一个是原生 NATIVE,剩下的为 weview
- 获得当前的上下文 current_context context
- 切换上下文 switch_to.context('WEBVIEW_XXXX')
webview 自动化演示代码 python 版
class TestWebView:
def setup_class(self):
capabilities = {
'platformName': 'android',
# python appium client 2.x 需要追加这个参数
'chromeOptions': {'w3c': False},
'appPackage': 'io.appium.android.apis',
'appActivity': 'io.appium.android.apis.ApiDemos',
'chromedriverExecutableDir': '/Users/seveniruby/projects/chromedriver/chromedrivers'
}
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', capabilities)
self.driver.implicitly_wait(10)
def test_webview(self):
self.driver.find_element(AppiumBy.ACCESSIBILITY_ID, 'Views').click()
self.driver.find_element(
AppiumBy.ANDROID_UIAUTOMATOR, "new UiScrollable(new UiSelector().scrollable(true))" +
".scrollIntoView(new UiSelector().text(\"WebView\"))").click()
# ['NATIVE_APP', 'WEBVIEW_io.appium.android.apis', 'WEBVIEW_com.tencent.mm:appbrand1']
print(self.driver.contexts)
wait = WebDriverWait(self.driver, 5)
# 个别app webview组件加载慢的时候不一定会及时出现webview上下文,需要加显式等待
wait.until(lambda driver: len(self.driver.contexts) > 1)
# 最好显式指定,在多进程同时有webview的时候,最后一个context不一定是当前app的webview
self.driver.switch_to.context('WEBVIEW_io.appium.android.apis')
self.driver.find_element(By.LINK_TEXT, 'i am a link').click()
assert 'I am some other page content' in self.driver.find_element(By.CSS_SELECTOR, 'body').text
webview 自动化演示代码 java 版
public class WebViewTest {
private static AndroidDriver driver;
@BeforeAll
public static void beforeAll() throws MalformedURLException {
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability("platformName", "android");
desiredCapabilities.setCapability("noReset", true);
desiredCapabilities.setCapability("appPackage", "io.appium.android.apis");
desiredCapabilities.setCapability("appActivity", "io.appium.android.apis.ApiDemos");
//设置保存有所有chromedriver的一个目录,让appium自动发现对应的版本
desiredCapabilities.setCapability("chromedriverExecutableDir",
"/Users/seveniruby/projects/chromedriver/chromedrivers");
URL url = new URL("http://127.0.0.1:4723/wd/hub");
driver = new AndroidDriver(url, desiredCapabilities);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
@Test
public void webview() {
driver.findElement(AppiumBy.accessibilityId("Views")).click();
driver.findElement(AppiumBy.androidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true))" +
".scrollIntoView(new UiSelector().text(\"WebView\"))")).click();
System.out.println(driver.getContextHandles());
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
wait.until(webDriver -> driver.getContextHandles().size() > 1);
driver.context("WEBVIEW_io.appium.android.apis");
driver.findElement(By.linkText("i am a link")).click();
assertThat(
driver.findElement(AppiumBy.cssSelector("body")).getText(),
containsString("I am some other page content")
);
}
}