Robotium学习笔记五

来源:互联网 发布:买网站域名去那里 编辑:程序博客网 时间:2024/05/10 02:50

在前面四篇笔记中基本完成了对Solo类大部分方法的记录,在这篇笔记中将对webView的操作做一个记录

还是老套路,先从获取所有的WebElement控件开始,Robotium主要是使用了一套JavaScript脚本,将脚本注入的网页中并执行响应的函数来获取Elements的,下面来看看代码


public WebElement getWebElement(By by, int index){int match = index + 1;WebElement webElement = waiter.waitForWebElement(by, match, Timeout.getSmallTimeout(), true);if(webElement == null) {if(match > 1){Assert.fail(match + " WebElements with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' are not found!");}else {Assert.fail("WebElement with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' is not found!");}}return webElement;}
这个方法主要是调用waitForElement(),继续往下看searcher.searchForWebElement()

这里也没有其他什么特别,一个计时器,然后调用searcher.searchForWebElement(by, minimumNumberOfMatches); 继续往下看,在这里这到了我想要的东西 getWebElement()

打开看到如下:

public ArrayList<WebElement> getWebElements(final By by, boolean onlySufficientlyVisbile){boolean javaScriptWasExecuted = executeJavaScript(by, false);if(config.useJavaScriptToClickWebElements){if(!javaScriptWasExecuted){return new ArrayList<WebElement>();}return webElementCreator.getWebElementsFromWebViews();}return getWebElements(javaScriptWasExecuted, onlySufficientlyVisbile);}
这里这首先调用了executeJavaScript(by, false);

public boolean executeJavaScript(final By by, boolean shouldClick){if(by instanceof By.Id){return executeJavaScriptFunction("id(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");}else if(by instanceof By.Xpath){return executeJavaScriptFunction("xpath(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");}else if(by instanceof By.CssSelector){return executeJavaScriptFunction("cssSelector(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");}else if(by instanceof By.Name){return executeJavaScriptFunction("name(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");}else if(by instanceof By.ClassName){return executeJavaScriptFunction("className(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");}else if(by instanceof By.Text){return executeJavaScriptFunction("textContent(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");}else if(by instanceof By.TagName){return executeJavaScriptFunction("tagName(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");}return false;}
可以看出根据By类传入不同类型的参数执行不同的js方法

private boolean executeJavaScriptFunction(final String function){final WebView webView = viewFetcher.getFreshestView(viewFetcher.getCurrentViews(WebView.class, true));if(webView == null){return false;}final String javaScript = prepareForStartOfJavascriptExecution();activityUtils.getCurrentActivity(false).runOnUiThread(new Runnable() {public void run() {if(webView != null){webView.loadUrl("javascript:" + javaScript + function);}}});return true;}

这个方法首先拿到一个webView对象,prepareForStartOfJavaScriptExecution()是将RobotiumWeb.js文件加载成字符串,并将RobotiumWebClient.class这个类的实例加载(这个类继承自google的WebChromeClient类,主要用来处理prompt)

最后LoadUrl 将js字符串和函数拼接成了一个大的js脚本 形成类似这样的脚本: 调用 allWebElement()函数

javascript:  function allWebElements() {      for (var key in document.all){          try{              promptElement(document.all[key]);   //调用promptElement(element)函数                  }catch(ignored){}      }      finished();    //执行完后,调用finished()函数  }    function promptElement(element) {      var id = element.id;      var text = element.innerText;      if(text.trim().length == 0){          text = element.value;      }      var name = element.getAttribute('name');      var className = element.className;      var tagName = element.tagName;      var attributes = "";      var htmlAttributes = element.attributes;      for (var i = 0, htmlAttribute; htmlAttribute = htmlAttributes[i]; i++){          attributes += htmlAttribute.name + "::" + htmlAttribute.value;          if (i + 1 < htmlAttributes.length) {              attributes += "#$";          }      }        var rect = element.getBoundingClientRect();      if(rect.width > 0 && rect.height > 0 && rect.left >= 0 && rect.top >= 0){          prompt(id + ';,' + text + ';,' + name + ";," + className + ";," + tagName + ";," + rect.left + ';,' + rect.top + ';,' + rect.width + ';,' + rect.height + ';,' + attributes);   //弹出包含id、text、name等字段的提示框      }  }  function finished(){      prompt('robotium-finished');    //弹出包含robotium-finished字符串的提示框,用于标识脚本注入执行结束  } 

生成一个prompt 含有 id,text,name等信息,在这里刚才注册的WebChromeClient就起到作用了,他可以处理这个 prompt(当网页弹出prompt时 会自动调用onjsPrompt方法)

public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult r) {if(message != null && (message.contains(";,") || message.contains("robotium-finished"))){if(message.equals("robotium-finished")){webElementCreator.setFinished(true);}else{webElementCreator.createWebElementAndAddInList(message, view);}r.confirm();return true;}else {if(originalWebChromeClient != null) {return originalWebChromeClient.onJsPrompt(view, url, message, defaultValue, r); }return true;}}
它使用 webElementCreator.createWebElementAndAddInList(message, view);将prompt中的信息解析存贮到 webElements中.

public void createWebElementAndAddInList(String webData, WebView webView){WebElement webElement = createWebElementAndSetLocation(webData, webView);if((webElement!=null)) webElements.add(webElement);}
private WebElement createWebElementAndSetLocation(String information, WebView webView){String[] data = information.split(";,");String[] elements = null;int x = 0;int y = 0;int width = 0;int height = 0;Hashtable<String, String> attributes = new Hashtable<String, String>();try{x = Math.round(Float.valueOf(data[5]));y = Math.round(Float.valueOf(data[6]));width = Math.round(Float.valueOf(data[7]));height = Math.round(Float.valueOf(data[8]));elements = data[9].split("\\#\\$");}catch(Exception ignored){}if(elements != null) {for (int index = 0; index < elements.length; index++){String[] element = elements[index].split("::");if (element.length > 1) {attributes.put(element[0], element[1]);} else {attributes.put(element[0], element[0]);}}}
createWebElementAndSetLocation这个方法是将 prompt中具体的参数封装成一个 Element对象包括 id,name 坐标等等这个坐标应该是 Element相对于WebView的坐标

回到WebUtils的getWebElements方法,在最后调用getWebElements(javaScriptWasExecuted, onlySufficientlyVisbile)

private ArrayList<WebElement> getWebElements(boolean javaScriptWasExecuted, boolean onlySufficientlyVisbile){ArrayList<WebElement> webElements = new ArrayList<WebElement>();if(javaScriptWasExecuted){for(WebElement webElement : webElementCreator.getWebElementsFromWebViews()){if(!onlySufficientlyVisbile){webElements.add(webElement);}else if(isWebElementSufficientlyShown(webElement)){webElements.add(webElement);}}}return webElements;}

getWebElements是筛选出当前可见的的Element并返回集合,就找到了需要的Element

下面来看看点击Element的操作,点击element其实和点击view的原理差不多,使用上面已经得到了element,中坐标属性就可以了

public void clickOnWebElement(By by, int match, boolean scroll, boolean useJavaScriptToClick){WebElement webElement = null;if(useJavaScriptToClick){webElement = waiter.waitForWebElement(by, match, Timeout.getSmallTimeout(), false);if(webElement == null){Assert.fail("WebElement with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' is not found!");}webUtils.executeJavaScript(by, true);return;}WebElement webElementToClick = waiter.waitForWebElement(by, match, Timeout.getSmallTimeout(), scroll);if(webElementToClick == null){if(match > 1) {Assert.fail(match + " WebElements with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' are not found!");}else {Assert.fail("WebElement with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' is not found!");}}clickOnScreen(webElementToClick.getLocationX(), webElementToClick.getLocationY(), null);}

关键的方法和view的click是一样的,其实最开始我在这里有一点不明白,就是获取element的坐标值,不知道是相对于webview还是相对于屏幕的,但是看到这里基本上可以判断这个坐标值是相对于屏幕的了.

Robotium的学习目前告一段落了,其实还有很多地方不是完全明白,可能也有很多说错的地方,希望大家直接指出来,欢迎拍砖



0 0
原创粉丝点击