selenium自动化测试原理和设计的分享

昨天参加了公司的一个自动化测试的分享,有一些收获,记录一下。

1.主流的web端的UI自动化测试工具

   基于浏览器API: selenium2.0,Watir(IE Driver)

  基于JS 进行驱动:selenium1.0,sahi(ruby)

  基于Windows GUI :QTP,AutoIt

2.实现原理(这里只列举第一种,第二种我没有实践,暂不研究)

基于浏览器API:

这里我在网上看了一下selenium2的实现原理,跟这个差不多。

参考:https://blog.csdn.net/ant_ren/article/details/7970793

selenium的工作原理:

1.用CS设计方式,将浏览器看作是remote  server,有它自己的端口,将selenium的脚本执行端看作client。

2.client发送http request(操作放在json里面)发送给web server端,转化为浏览器的API,再封装成执行命令CommandExecutor ,发给浏览器去用native的操作执行

3.浏览器执行后,再返回给client

简化为:webdriver把浏览器的原生API包装了一下,通过conmmandExecutor来给浏览器发送http request请求(操作写在json里面),通过设置的端口,去请求浏览器,将发送的请求转化成浏览器的原生的命令,再将浏览器的返回,装进httpResponse里面,发回给客户端。

 

画了一张图

 

其他博客里面,引用的开发者的图

 

3.UI自动化的原则

  • 不依赖环境,不改变环境
  • 隔离变量和不变量
  • 代码尽可能复用

4.使用的设计模式

  三层:

  • 界面表示层:一个页面封装到一个类中,一个方法对应一个控件,主要是查找控件,复杂控件操作,比如表格,需要再界面表示层实现
  • 业务逻辑层:调用界面表示层的控件操作,完成业务逻辑,一般一个函数封装一个简单的业务操作。
  • 测试用例层:调用业务层的函数完成测试,并验证结果,尽量不依赖环境,不破坏环境,不要直接调用界面层函数

5.源码解读,我用的是appium,不过appium和selenium是同源的,可以用来参考。

  findElements代码

    Response response = execute(DriverCommand.FIND_ELEMENTS,
        ImmutableMap.of("using", by, "value", using));

  

  @SuppressWarnings("unchecked")
  protected List<WebElement> findElements(String by, String using) {
    if (using == null) {
      throw new IllegalArgumentException("Cannot find elements when the selector is null.");
    }

    Response response = execute(DriverCommand.FIND_ELEMENTS,
        ImmutableMap.of("using", by, "value", using));
    Object value = response.getValue();
    List<WebElement> allElements;
    try {
      allElements = (List<WebElement>) value;
    } catch (ClassCastException ex) {
      throw new WebDriverException("Returned value cannot be converted to List<WebElement>: " + value, ex);
    }
    for (WebElement element : allElements) {
      setFoundBy(this, element, by, using);
    }
    return allElements;
  }

  findElement 返回的是执行语句的 response,执行语句如下,返回值是response

  protected Response execute(String driverCommand, Map<String, ?> parameters) {
    Command command = new Command(sessionId, driverCommand, parameters);
    Response response;

    long start = System.currentTimeMillis();
    String currentName = Thread.currentThread().getName();
    Thread.currentThread().setName(
        String.format("Forwarding %s on session %s to remote", driverCommand, sessionId));
    try {
      log(sessionId, command.getName(), command, When.BEFORE);
      response = executor.execute(command);
      log(sessionId, command.getName(), command, When.AFTER);

      if (response == null) {
        return null;
      }

      // Unwrap the response value by converting any JSON objects of the form
      // {"ELEMENT": id} to RemoteWebElements.
      Object value = converter.apply(response.getValue());
      response.setValue(value);
    } catch (SessionNotFoundException e){
      throw e;
    } catch (Exception e) {
      log(sessionId, command.getName(), command, When.EXCEPTION);
      String errorMessage = "Error communicating with the remote browser. " +
          "It may have died.";
      if (driverCommand.equals(DriverCommand.NEW_SESSION)) {
        errorMessage = "Could not start a new session. Possible causes are " +
            "invalid address of the remote server or browser start-up failure.";
      }
      UnreachableBrowserException ube = new UnreachableBrowserException(errorMessage, e);
      if (getSessionId() != null) {
        ube.addInfo(WebDriverException.SESSION_ID, getSessionId().toString());
      }
      if (getCapabilities() != null) {
        ube.addInfo("Capabilities", getCapabilities().toString());
      }
      throw ube;
    } finally {
      Thread.currentThread().setName(currentName);
    }

    try {
      errorHandler.throwIfResponseFailed(response, System.currentTimeMillis() - start);
    } catch (WebDriverException ex) {
      if (parameters != null && parameters.containsKey("using") && parameters.containsKey("value")) {
        ex.addInfo(
            "*** Element info",
            String.format(
                "{Using=%s, value=%s}",
                parameters.get("using"),
                parameters.get("value")));
      }
      ex.addInfo(WebDriverException.DRIVER_INFO, this.getClass().getName());
      if (getSessionId() != null) {
        ex.addInfo(WebDriverException.SESSION_ID, getSessionId().toString());
      }
      if (getCapabilities() != null) {
        ex.addInfo("Capabilities", getCapabilities().toString());
      }
      Throwables.propagate(ex);
    }
    return response;
  }

  response的核心代码如下:执行command,然后用转化器将response的value转化成语句使用的代码

response = executor.execute(command);
……
 Object value = converter.apply(response.getValue());
      response.setValue(value);

  这里的converter.apply,是JsonToWebElementConverter的方法,就是用来把返回的json串转化为element的转化器

  public Object apply(Object result) {
    if (result instanceof Collection<?>) {
      Collection<?> results = (Collection<?>) result;
      return Lists.newArrayList(Iterables.transform(results, this));
    }

    if (result instanceof Map<?, ?>) {
      Map<?, ?> resultAsMap = (Map<?, ?>) result;
      if (resultAsMap.containsKey("ELEMENT")) {
        RemoteWebElement element = newRemoteWebElement();
        element.setId(String.valueOf(resultAsMap.get("ELEMENT")));
        element.setFileDetector(driver.getFileDetector());
        return element;
      } else if (resultAsMap.containsKey("element-6066-11e4-a52e-4f735466cecf")) {
        RemoteWebElement element = newRemoteWebElement();
        element.setId(String.valueOf(resultAsMap.get("element-6066-11e4-a52e-4f735466cecf")));
        element.setFileDetector(driver.getFileDetector());
        return element;
      } else {
        return Maps.transformValues(resultAsMap, this);
      }
    }

    if (result instanceof Number) {
      if (result instanceof Float || result instanceof Double) {
        return ((Number) result).doubleValue();
      }
      return ((Number) result).longValue();
    }

    return result;
  }

  

  

  

appium原理参考https://www.cnblogs.com/csj2018/p/9937511.html

posted @ 2018-06-15 14:51  头鹰在学习  阅读(410)  评论(0编辑  收藏  举报