缘由

当前做的项目中很多页面存在一定的共性,所以思考了一下 Web 自动化的可行性,
目前基本上做了一小块信息抽取的功能,目的是

  1. 给到产品验收
  2. 做版本对比
  3. 后续可以做 PRD 对比,即拿文档中的要求直接与开发出来的结果进行对比

在做 UI 自动化的过程中,脑子里迸出来一个想法,是不是可以同时对接口数据进行校验?
网上一搜,丫的还真有,还在 6 年多前就有了解决方案
于是有了本文

技术基础

  1. selenium
  2. xpath
  3. testNG
  4. browsermob-proxy
  5. java
  6. maven

Pom

<properties>
    <aspectj.version>1.8.10</aspectj.version>
    <allure.version>1.5.4</allure.version>
    <testng.version>6.11</testng.version>
    <okhttp3.version>3.10.0</okhttp3.version>
    <lombok.version>1.16.18</lombok.version>
    <slf4j.version>1.7.25</slf4j.version>
    <logback.version>1.2.3</logback.version>
    <assertj.version>3.8.0</assertj.version>
    <fastjson.version>1.2.47</fastjson.version>
    <mysql.connector.version>8.0.11</mysql.connector.version>
    <jedis.version>2.9.0</jedis.version>
    <java.version>1.8</java.version>
</properties>

<dependencies>

    <dependency>
        <groupId>net.lightbody.bmp</groupId>
        <artifactId>browsermob-core</artifactId>
        <version>2.1.5</version>
    </dependency>

    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>3.141.59</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>${fastjson.version}</version>
    </dependency>

    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <version>3.0.6</version>
    </dependency>

    <dependency>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-core</artifactId>
        <version>${assertj.version}</version>
    </dependency>

    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>${jedis.version}</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.connector.version}</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>${logback.version}</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>${logback.version}</version>
    </dependency>

    <dependency>
        <groupId>org.codehaus.janino</groupId>
        <artifactId>janino</artifactId>
        <version>3.0.7</version>
    </dependency>

    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>${testng.version}</version>
    </dependency>

    <dependency>
        <groupId>ru.yandex.qatools.allure</groupId>
        <artifactId>allure-testng-adaptor</artifactId>
        <version>${allure.version}</version>
    </dependency>

    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>${okhttp3.version}</version>
    </dependency>

    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>logging-interceptor</artifactId>
        <version>${okhttp3.version}</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>23.0</version>
    </dependency>

</dependencies>

主要思路

import com.wz.pages.Login;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.proxy.CaptureType;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.Test;

import java.io.File;
import java.io.IOException;

public class Demo {

    @Test
    public void t1() throws IOException {
//        System.setProperty ("jsse.enableSNIExtension", "false");
        BrowserMobProxy browserMobProxy = new BrowserMobProxyServer();
        browserMobProxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);
        browserMobProxy.start();

        Proxy seleniumProxy = ClientUtil.createSeleniumProxy(browserMobProxy);

        System.setProperty("webdriver.chrome.driver", Demo.class.getResource("/chromedriver").getPath());
        ChromeOptions chromeOptions = new ChromeOptions();

        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(CapabilityType.PROXY, seleniumProxy);
        capabilities.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, false);
        chromeOptions.merge(capabilities);

        WebDriver driver = new ChromeDriver(chromeOptions);

        browserMobProxy.newHar("https://wzzzzzzzzzzzz.com");
        Login.loginAccount(driver, "https://wzzzzzzzzzzzz","01999888777", "Clark@01999888777");

        Har har = browserMobProxy.getHar();
        har.writeTo(new File("demo.har"));

        driver.close();

    }
}

还是直接上代码吧,可以看出来,

  1. 配置代理
  2. 设置需要抓取请求体,响应体 ==> 这里可以不设置,那么抓出来 har 包里面就没有请求体,响应体信息
  3. 配置 chrome 参数,启动 chrome
  4. 进行 web 测试
  5. web 测试结束后,保存抓包数据

结果

{
  "pageref": "https://wzzzzzzzzzzzz.com",
  "startedDateTime": "2019-02-27T13:25:31.188Z",
  "request": {
    "method": "POST",
    "url": "https://wzzzzzzzzzzzz.com/tenant/v1/api/user/account/login",
    "httpVersion": "HTTP/1.1",
    "cookies": [

    ],
    "headers": [

    ],
    "queryString": [

    ],
    "postData": {
      "mimeType": "application/x-www-form-urlencoded",
      "params": [
        {
          "name": "account",
          "value": "01999888777",
          "comment": ""
        },
        {
          "name": "password",
          "value": "Clark@01999888777",
          "comment": ""
        }
      ],
      "comment": ""
    },
    "headersSize": 505,
    "bodySize": 48,
    "comment": ""
  },
  "response": {
    "status": 0,
    "statusText": "",
    "httpVersion": "unknown",
    "cookies": [

    ],
    "headers": [

    ],
    "content": {
      "size": 0,
      "mimeType": "",
      "comment": ""
    },
    "redirectURL": "",
    "headersSize": -1,
    "bodySize": -1,
    "comment": "",
    "_error": "No response received"
  },
  "cache": {

  },
  "timings": {
    "comment": "",
    "dns": 0,
    "connect": 84,
    "send": 0,
    "wait": 0,
    "receive": 0,
    "blocked": 30,
    "ssl": 45
  },
  "serverIPAddress": "139.198.176.127",
  "comment": "",
  "time": 115
}

有了 har 包,再对其进行解析,就可以做响应校验,更多的数据校验了

问题

  1. 有看到 BrowserMobProxy 可以设置过滤器,但是暂时没实践出来,也没有搜索到相关的例子, github 官网上的不像是过滤器,是拦截器,而我想要 XHR,或是按 url 地址进行正则过滤 ==> 暂时的解决方法:可以对 Har 的内容进行过滤
  2. 之前还有一个想法是通过 selenium 调用 javascript 方法或 chrome 的 api 来获取 XHR 请求数据,没试成功
  3. 看到别人写好的 Har 代码,再看看自己的,我日,咋没早点发现呢,花了自己好几天时间,直接引他的包就完了, 当然在这过程中也踩了坑学习到了如何对枚举类进行反序列化
  4. 当前的测试环境是 HTTPS 协议的,在日志中报 SSL 的错误,虽然不影响测试,但是就是感觉别扭 io.netty.handler.codec.DecoderException: javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name

参考

  1. https://github.com/lightbody/browsermob-proxy
  2. https://sites.google.com/a/chromium.org/chromedriver/system/app/pages/search?scope=search-site&q=Request


↙↙↙阅读原文可查看相关链接,并与作者交流