Athrun框架WebView自动化测试源码解析

虽然Athrun对WebView的支持不是很完美,但一些基本功能还是可以完成的,比如:查找一个名字为“HelloWeb”的Web Element,并将其值改为“Hello World!”。相应的用法如下:

 

webview.typeTextInWebElement(By.name("HelloWeb"), "Hello World!", 0);

 

 

一 WebView自动化测试的应用与原理

1 进入Web页面

首先,它的执行步骤和Native View的操作步骤是一致的,通过形如以下的代码进入真正的Web页面:

 

  findElementByText("WebView").doClick();
  WebViewElement webview = findWebElementById("mywebview", WebViewElement.class);

 

 

2 查找Web元素

接下来,我们需要在WebView页面上找到相应的子元素。Athrun框架中封装了一个By类,并扩展了多个内部子类用于封装各种Web子控件的查找方法,如:Id ,Xpath ,CssSelector,ClassName,Name,Text,TagName等。请看以下例子:

WebElement webEle =  webview.getWebElement(By.className("btn-bg"),0);

 

 

上述例子的具体含义为:通过ClassName为“btn-bg”来查找WebElement。

那为什么通过这个ClassName就能找到呢?这个问题是最关键。请看下面的调用顺序:

 

getWebElement     

waitForWebElement  

searchForWebElement     

getCurrentWebElementsgetViewFromList

 

其实直接返回WebElement的是searchForWebElement方法,我们看看它的具体实现:

 /**
     * Searches for a web element.
     *
     * @param by the By object.
     * @param minimumNumberOfMatches the minimum number of matches that are expected to be shown. 0 means any number of matches
     * @param timeout the amount of time in milliseconds to wait
     * @param scroll true if scrolling should be performed
     * @return true if the web element is found
     */

    private WebElement searchForWebElement(final By by, int minimumNumberOfMatches, int timeout, boolean scroll){

        if(minimumNumberOfMatches < 1){
            minimumNumberOfMatches = 1;
        }

        List<WebElement> viewsFromScreen = webUtils.getCurrentWebElements(by);
        addViewsToList (webElements, viewsFromScreen);

        return getViewFromList(webElements, minimumNumberOfMatches);
    }

 

 

searchForWebElement中,先调用getCurrentWebElements(by)获取所有条件符合by的WebElements,然后通过getViewFromList获取webElements列表中符合参数minimumNumberOfMatches的WebElement。

 

getViewFromList挺好理解的,关键是getCurrentWebElements这个方法。它是怎么做到的呢?

 /**
     * Returns an ArrayList of WebElements of the specified By object currently shown in the active WebView.
     *
     * @param by the By object.
     * @return an ArrayList of the WebElement objects currently shown in the active WebView
     */

    public ArrayList<WebElement> getCurrentWebElements(final By by) {
        boolean javaScriptWasExecuted = executeJavaScript(by);

        return getSufficientlyShownWebElements(javaScriptWasExecuted);
    }

 

 

上文中的executeJavaScript和getSufficientlyShownWebElements才是解决问题的突破口。

executeJavaScript:在java中执行js脚本

getSufficientlyShownWebElements:保存所有完全显示在界面上的web元素。

 

executeJavaScript方法做了哪些工作呢?

I  通过读取Athrun框架下的WebView.js(WebUtils-> getJavaScriptAsString)文件,并将读取的内容保存在一个String中。而WebView.js中定义了各种查找页面元素的方法,如:

function id(id)、

function xpath(xpath)、

function cssSelector(cssSelector)等。

 

II通过By的具体类型(Id,Name,CssSelector等),拼凑出一个function的调用,其中包括function名及其参数,并以String的类型返回,如:

executeJavaScriptFunction("id(\"" + by.getValue() + "\");")中的

"id(\"" + by.getValue() + "\");"

 

 

III 在方法executeJavaScriptFunction方法中,将I和II返回的结果拼凑,并加上前缀“javascript:”,最终就变成:

Javascript+ WebView.js原文 id(by.getValue())并将其传给webView.loadUrl方法,如:

webView.loadUrl("javascript:" + javaScript + function);

 

 

 

 

因为id(String)方法在WebView.js中已声明定义了,所以是合法调用。

 

通过执行executeJavaScript方法,找到了符合by的所有web元素,接下来就调用getSufficientlyShownWebElements方法将所有显示在页面上的元素保存在一个数据中,也就的到了getCurrentWebElements所要的结果了,所以想要的元素也找到了,所以就可以触发点击事件,输入文本事件了。

 

3 触发动作

获取到WebElement后,就可以获取其Location,如:

webElement.getLocationX()

webElement.getLocationY()

然后就可以clickOnScreen了,click其实也是通过Instrumentation发送event事件的。如下所示:

/**
     * Clicks on a given coordinate on the screen.
     *
     * @param x
     *            the x coordinate
     * @param y
     *            the y coordinate
     */
    public void clickOnScreen(float x, float y) {
        long downTime = SystemClock.uptimeMillis();
        long eventTime = SystemClock.uptimeMillis();
        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
                MotionEvent.ACTION_DOWN, x, y, 0);
        MotionEvent event2 = MotionEvent.obtain(downTime, eventTime,
                MotionEvent.ACTION_UP, x, y, 0);
        try{
            inst.sendPointerSync(event);
            inst.sendPointerSync(event2);
        }catch(SecurityException e){
            Assert.assertTrue("Click can not be completed!", false);
        }
    }

 

现在整个WebView的自动化测试就完成了。

 

总结:WebView自动化测试,其实就是Java执行Js的一系列操作。

 

 

相关推荐