zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    LNOI2014LCA(树链剖分+离线操作+前缀和)
    CDQ分治与整体二分学习笔记
    BJWC2018上学路线
    NOIP2013火柴排队
    SHOI2008仙人掌图(tarjan+dp)
    作诗(分块)
    COGS314. [NOI2004] 郁闷的出纳员
    bzoj 1691: [Usaco2007 Dec]挑剔的美食家
    COGS1533.[HNOI2002]营业额统计
    bzoj1208: [HNOI2004]宠物收养所
  • 原文地址:https://www.cnblogs.com/zhizhiyin/p/9187280.html
Copyright © 2011-2022 走看看