Skip to content

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 安装

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 版本选择

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")
        );

    }
}