接口测试 接口自动化测试的一些思考和我自己的一整套处理方案 (java 向)

luoy · 2020年12月16日 · 最后由 ganker 回复于 2022年03月18日 · 12272 次阅读

接口自动化测试的一些思考

前言

之前社区一直讨论很火的接口测试框架实现,到底是高大上的傻瓜式接口平台好用,还是全脚本的编写的接口框架好这两个方案其实我都有考虑过,两个方案各有优缺点, 我个人理解就是接口平台优点可以降低学习成本,快速使用, 全脚本编写接口框架的优点为灵活性高,各种疑难杂症的用例都能解决,而且拓展性好

在思考这两条路上,我差点做了接口平台,主要基于两点,第一点就是我上家公司,在接口平台还没火起来还没这个概念的时候,我写的接口测试框架基本上是全代码实现,在后面的大面积应用过程中,我也感觉到了很多缺点,比如分层不清晰, 大量用例维护心累等问题.第二点是接口平台能在像领导汇报时候提升逼格,出去面试时候也能吹吹

最后的结果就是何不两种方案结合下,可以提供一个测试数据模板直接把用例编写好,然后代码端又提供很好的拓展,有了这个想法就开始了我的撸码生活

技术选型

主要考虑到一些接口需要支持的东西,然后从这方面开始选型

首先技术栈是 java, 那底层支持就好选了, springBoot + maven 搞起来

java 测试框架嘛 testng 搞起来, 支持多线程多纬度运行测试用例,支持重试,支持数据驱动等等等等

测试报告 allure, 和 testng 完美兼容,且有现成 jenkins 插件

测试数据 yaml 保存

http 请求 restassured 这个 http 请求库基本上为测试而生

选型基本敲定,从底层到测试报告到 ci/cd

版本迭代

1.最初版本 0.0.1

1.1 具体实现方案为编写一个接口 api, 该 api 定义 baseUrl, 且通过方法与注解来描述里面的接口,返回一个 restassured 的 response, 然后通过代理类解析该接口生成一个具体实现类注入 spring 容器中

1.2 测试用例继承 AbstractTestNGSpringContextTests, 用@SpringBootTest开启 spring 容器

1.3 测试用例可用@Autowired注入接口类,然后像调用普通方法一样调用

大体代码如下:

接口定义类:

@HttpServer(baseUrl = "https://testplatform.com.cn/testool-api")
@Filters({RestAssuredLogFilter.class, RequestLoggingFilter.class, ResponseLoggingFilter.class})
public interface UserApi {

    @Get(url = "/menu/list", descriptoin = "获取所有菜单")
    Response getMenus();

    @Get(url = "/menu/byPhone", descriptoin = "根据手机号码查询菜单")
    Response byPhone(@ParamsForm("phone") String phone);

    @Get(url = "/role/list", descriptoin = "分页查询角色")
    Response getRoleListPage(@Head("pageNo") String pageNo, @Head("pageSize") String pageSize, @ParamsForm("roleName") String roleName);

    @Post(url = "/role/add", descriptoin = "增加用户角色")
    Response addRole(@ParamsJson String json);
}

测试用例类:

@Features("ces")
@Stories("测试Http")
public class TestoolApiTest extends BaseApiTestCase {
    @Autowired
    private UserApi userApi;

    @Severity(SeverityLevel.CRITICAL)
    @Description("测试api测试")
    @Title("TestoolUserApi")
    @Test(groups = "test-groups-1", dataProvider = "loadDataParams")
    //失败重试两次
    @RetryCount(count = 2)
    @DataParams({"1,10,"})
    public void getRoleListPage(String pageNo, String pageSize, String roleName) {
        Response response = userApi.getRoleListPage(pageNo, pageSize, roleName);
        response.then()
                .statusCode(200)
                .body("code", equalTo(200))
                .body("success", equalTo(true));
    }
}

baseTestCase 主要做一些继承和参数化

//properties属性指定本地测试需要用到的配置文件
//本地运行时,需要设置properties值为具体的某个配置文件
@SpringBootTest(properties = {"spring.profiles.active=local"})
//通过maven命令运行时需要把该参数去掉
//@SpringBootTest
public abstract class BaseTestCase extends AbstractTestNGSpringContextTests {
    @DataProvider
    public static Object[][] loadDataParams(Method method){
        DataParams dataParams =  method.getAnnotation(DataParams.class);

        AssertUtils.notNull(dataParams, method.getName() + "方法添加了DataProvider数据驱动,没有添加@DataParams注解");

        String[] values = dataParams.value();

        String split = dataParams.splitBy();

        List<Object[]> result = Lists.newArrayList();

        for (int i = 0; i < values.length; i++) {
            String[] v1 = values[i].split(split, -1);
            result.add(v1);
        }

        return wildcardMatcher(Utils.listToArray(result));
    }
}

主要注解意义:

- @HttpServer: 接口类上注解,非必填,可设置整个接口类的baseUrl
- @Filters: 用于传递reat-assured过滤器注解,接收一个io.restassured.filter.Filter类数组,
 如果注释在类上,则整个类接口都会使用该注解里面的过滤器,如果注解在方法上,则作用域该方法
- @Get/@Post: 定义接口请求方法,作用于方法上,需要设置接口请求url,接口简介,如果url为带http/https则最终请求url为该url,
如果不带http/https,则最终请求url为baseUrl + 该url,该注解可设置请求类型:content-type与请求字符编码集charset
- @HeadMap 作用于请求参数上,设置请求头,参数类型:Map
- @Head 作用于请求参数上,设置请求头,需要设置value值,请求时候value为key,参数为value,可设置多组,如果
同时设置@HeadMap与@Head则会合并为一个map
- @paramsForm 作用于请求参数上,设置请求参数,为k-v类型,注解vaule为请求k,参数为v,可多个,合并处理
- @ParamsJson 作用于请求参数上,设置请求参数,json模式,请求方式为json
- @ParamsMap 作用于请求参数上,设置请求参数,参数类型:Map

然后通过 testng 的 xml 配置文件配置运行

2.迭代 1.0.0(直接跳到现在版本,中间迭代太多)

主要问题是写一个用例耗时太多,需要改太多东西, 然后就有了思考空间, 把不需要的细节隐藏

2.1 引入 yaml 描述接口与用例

name: login
type: json
description: 登录成功
url: /login
method: POST
headers:
  x-request-client-imei: "222222222222"
requests:
  {
    "phone": "${phone, 13000000001}",
    "code": "0000"
  }
setup:
  - method: createTimestamp
  - method: setUptest
    args: ${request}
teardown:
  - method: teardowm
    args: args1111, args222
  - method: teardowm1
    args: ${response}, ${timestamp}
onFailure:
  - method: onFailure
    args: args1111, args222
validate:
  eq: ["result": 0, "error_code": "0"]
  notNull: ["data.token"]
  plugin: 
    - method: "teardowm"
      args: args1111, ${orderId}
saveGlobal: ["orderId": "response.data.token"]
saveMethod: ["orderId": "response.data.token"]
saveClass: ["orderId": "response.data.token"]
saveThread: ["orderId": "response.data.token"]
parameters:
  - name: login-phone-unregistered
    description: 手机号未注册
    headers:
    requests:
      "phone": "13000000009"
      "code": "0000"
    validate:
    eq: ["result": 1]
  - name: login-phone-not-found
    description: 手机号不存在
    requests:
      "phone": "10000000000"
      "code": "0000"
    validate:
      eq: ["result": 1]
  - name: login-code-length-error
    description: 验证码长度错误
    requests:
      "phone": "10000000000"
      "code": "000"
    validate:
      eq: ["result": 1]
  - name: login-code-error
    description: 验证码错误
    requests:
      code: "0001"
    validate:
      eq: ["result": 1]

2.2 BaseHttpClient , Response 类的一些处理

- BaseHttpClient对象方法
     wait(),wait(TimeUnit unit, long interval) 用于设置请求接口前的等待时间
     saveAsk(),saveGlobal(), saveTest(),saveSuite() 用于往不同生命周期保存一个缓存,saveAsk为该请求生命周期
     doHttp(BaseModel model)接口调用,入参为model,SINGLE模式时候直接传入方法入参BaseModel即可
     doHttp(String modelName)接口调用,入参为modelName, MULTIPLE模式时候传入modelName即可
   - Response对象方法
     then(): 语法糖,无特殊意义,只用作链式调用标明
     statusCode(): 用于断言接口返回code
     validate(): 断言方法
     eq(): 硬编码断言相等
     eqByPath(): 硬编码断言相等,值取jsonpath,xpath
     validatePlugin(): 硬编码断言,用于调用方法
     saveGlobal(), saveTest(),saveSuite() : 结果保存不同维度方法
     onFailure(BaseFailHandle failHandle): validate()断言失败后会执行的方法,所以必须在validate()方法后调用,入参为BaseFailHandle接口,需要实现该接口并且重写handle(T t)方法
     onFailure(Class clazz): 同上
     extract(): 用于取值
     processor(BaseProcessorHandle processorHandle)
     processor(Class clazz):用于该调用该接口后一些自定义处理,如订单行程需要一分钟,入参为BaseProcessorHandle接口,需要实现该接口并且重写processor(T t)方法
     wait(): 接口执行完后等待时间
     done(): 用于处理结束,抛出validate()异常,如没吊用extract()方法取值的话该方法为链式调用结尾必须调用
     auto(): 自动解析yaml文件所有内容
     auto(int httpStatusCode): 自动解析yaml文件所有内容,手动设置httpStatusCode
     autoExcludeDone(): 自动解析yml文件, 但是不会自动调用done()方法结束,需要手动调用done结束,主要用于给该http请求添加更多的自定义处理

2.3 然后 testng 类 configuration 配置方法不支持参数化,对此进行的一些加强处理

@ApiBeforeMethod
   @ApiBeforeClass
   @ApiBeforeSuite
   @ApiAfterMethod
   @ApiAfterClass
   @ApiAfterSuite
   主要结合@DataModel, @DataFile, @DataParams 当配置方法入参使用

2.4 数据驱动核心注解@DataModel

/**
 *
 * <p>数据驱动 yaml模式
 * <p> 当Format= SINGLE, vaule = {"login", "login1"}
 *     表示该用例是单接口模式
 *     用例入参模型为: BaseModel
 *     入参值为yaml文档name对应的login与login1和这两个name下的所有parameters
 *     eg.
 *     @DataModel(value = {"login", "login1"}, format = DataModel.Format.SINGLE)
 *     public void login(BaseModel model) {
 *         apiClient.doHttp(model).auto();
 *     }
 *
 * <p> 当Format= MULTIPLE, vaule = {"login", "profile"}
 *     表示该用例是业务流模式,只会运行一次,业务对应入参可从
 *     用例入参模型为: MultipleModel
 *     value可省略
 *     eg.
 *     @DataModel(format = DataModel.Format.MULTIPLE)
 *     public void login1(MultipleModel model) {
 *         driverApiClient.doHttp(model.getModel("login")).auto();
 *         driverApiClient.doHttp(model.getModel("profile")).auto();
 *     }
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.METHOD})
public @interface DataModel {
    /** 取yaml的name */
    String[] value() default {};

    /** yaml文件名字,支持多个文件引入,默认路径为 resources下的data.yml */
    String[] path() default {"data.yml"};

    /** 模式 */
    DataModel.Format format() default Format.MULTIPLE;

    enum Format
    {
        /**单接口**/
        SINGLE,
        /**串行**/
        MULTIPLE
    }

2.5 spring 功能支持多环境集成与中间的一些配置解释

application-qa.yml,application-uat.yml 区分环境配置文件,最终会根据使用环境默认合并到application.yml

- application.yml

  - notification节点: 配置通知类型
  - retry节点: 配置用例失败重试

- application-qa.yml,application-uat.yml 

  - httpurl节点: 配置接口层接口类上面@HttpServer注解中baseurl代表值baseurl直接用${driverapi.url}调用即可

2.6 测试结果通知支持钉钉,邮件等,通过 application.yml notification 节点配置

2.7 参数化说明

yaml模板中支持参数化|jsonpath|xpath等写法,如${phone, 13000000001}, 该用法为该参数化值设置一个default值,如果缓存中无该值,那就取default值
jsonpath一般用于validate与saveGlobal中,用于取返回值校验与保存
setup支持${response}参数化,${response}会转换成BaseModel
teardown支持${response}参数化,${response}会转换成Response

2.8 因为是 springboot 架构, 可直接集成 JdbcTemplate,redisTemplate,mongoTemplate 等

2.9 两个生命周期监听器用于拓展

public interface HttpPostProcessor extends PostProcessor{

    /**
     * http请求之前处理器
     * @param context
     */
    void requestsBeforePostProcessor(HttpContext context);

    /**
     * http请求之后处理器
     * @param context
     */
    void responseAfterPostProcessor(HttpContext context);


    /**
     * http请求后 对response对象进行各种处理后的处理器
     * 在{@link Response done()}内调用
     * @param context
     */
    void responseDonePostProcessor(HttpContext context);
public interface TestNgLifeCyclePostProcessor extends PostProcessor{

    /**
     * 测试方法执行前执行
     * @param result
     */
    void onTestMethodStartBeforePostProcessor(ITestResult result);

    /**
     * 测试方法执行成功后执行
     * @param result
     */
    void onTestMethodSuccessAfterPostProcessor(ITestResult result);


    /**
     * 测试方法执行失败后执行
     * @param result
     */
    void onTestMethodFailureAfterPostProcessor(ITestResult result);

    /**
     * 跳过测试方法后执行
     * @param result
     */
    void onTestMethodSkippedAfterPostProcessor(ITestResult result);

    /**
     * 在实例化测试类之后且在调用任何配置方法之前调用
     * @param context
     */
    void onTestClassInstantiationAfterPostProcessor(ITestContext context);

    /**
     * 在运行所有测试并调用其所有配置方法之后调用
     * @param context
     */
    void onAllTestMethodFinishAfterPostProcessor(ITestContext context);

    /**
     * suite执行之前执行 对应test.xml suite标签
     * @param suite
     */
    void onSuiteStartBeforePostProcessor(ISuite suite);

    /**
     * suite执行后执行 对应test.xml suite标签
     * @param suite
     */
    void onSuiteFinishAfterPostProcessor(ISuite suite);

    /**
     * 配置方法运行前执行(配置方法: beforeTest,AfterTest等)
     * @param result
     */
    void onConfigurationStartBeforePostProcessor(ITestResult result);

    /**
     * 配置方法执行成功时执行
     * @param result
     */
    void onConfigurationSuccessAfterPostProcessor(ITestResult result);

    /**
     * 配置方法执行失败时执行
     * @param result
     */
    void onConfigurationFailureAfterPostProcessor(ITestResult result);

    /**
     * 配置方法跳过时执行
     * @param result
     */
    void onConfigurationSkipAfterPostProcessor(ITestResult result);

2.10 完美兼容 allure 注解

2.11 完美兼容 testng 用法, 只做 testng 增强

2.12 完美兼容 maven, 指定 testng 用例执行, 支持多种 testng 运行纬度: XML Files, Groups, Parallel,verbosity,'testnames' in test tag

2.13 提供 com.ly.core.actuator.TestNgRun 编码方式运行用例

2.14 提供一个 har 格式转换为 yaml 用例数据 (charles 导出.har 文件转换为 yaml 格式)

2.15 jenkins 支持

3. example

3.1 先编写 yaml (yaml 默认放在 resource 目录下,也可直接指定路径)

testCase:
-   name: login
    description: 登录
    type: json
    url: /v1/security/login
    method: POST
    setup:
      - method: createTimestamp
      - method: setUptest
        args: ${request}
    headers:
        timestamp: '1589441750400'
        os: android9
        content-type: application/json;charset=UTF-8
        ver: 2.2.0
    requests:
        code: '0000'
        phone: '13000000001'
    validate:
        notNull: [result]
        eq: [result: 0]
        len: [result: 1]
        hasKey: [data: token]
        hasValue: [data: 4]
    saveMethod: ["token": "data.token"]
    teardown:
      - method: teardowm
        args: args1111, args222
      - method: teardowm1
        args: ${response}, ${timestamp}
    parameters:
      - name: login-phone-unregistered
        description: 手机号未注册
        requests:
          "phone": "13000000009"
          "code": "0000"
        validate:
          eq: ["result": 1]
      - name: login-phone-not-found
        description: 手机号不存在
        requests:
          "phone": "10000000000"
          "code": "0000"
        validate:
          eq: ["result": 1]
      - name: login-code-length-error
        description: 验证码长度错误
        requests:
          "phone": "10000000000"
          "code": "000"
        validate:
          eq: ["result": 1]
      - name: login-code-error
        description: 验证码错误
        requests:
          code: "0001"
        validate:
          eq: ["result": 1]
      - name: login-phone-isNull
        description: phone字段不存在
        requests:
          "phone": null
          "code": "0000"
        validate:
          eq: ["result": 1]

-   name: index
    description: 首页
    type: form
    url: /v1/driver/index
    method: GET
    headers:
        authorization: ${token}
        timestamp: '1589441751257'
        os: android9
        ver: 2.2.0
    requests: {}
    validate:
        notNull:
        - result
        eq:
        -   result: 0

3.2 编写 apiClient, http.test.url 写在配置文件中

@HttpServer(baseUrl = "${http.test.url}")
@Filters({RestAssuredLogFilter.class})
public interface DefaultApiClient extends BaseHttpClient{
}

3.3 编写用例

@Story("登录模块接口")
public class ExampleApiTestCase extends BaseDefaultApiTestCase {

    @DataModel(value = {"login"},
            format = DataModel.Format.SINGLE,
            path = {"example.yml"})
    @ApiBeforeClass
    public void beforeClass(BaseModel model) {
        System.out.println("===========beforeClass============: " + model);
    }

    @DataModel(value = {"login"},
            format = DataModel.Format.SINGLE,
            path = {"example.yml"})
    @ApiAfterMethod
    public void afterMethod(BaseModel model) {
        System.out.println("=============afterMethod==========" + model);
    }



    @Severity(SeverityLevel.CRITICAL)
    @Description("登录")
    @Test(groups = "example")
    @DataModel(value = {"login"},
            format = DataModel.Format.SINGLE,
            path = {"example.yml"})
    public void login(BaseModel model) {
        apiClient.doHttp(model).auto();
    }

    @Severity(SeverityLevel.CRITICAL)
    @Description("获取司机信息")
    @Test(groups = "example")
    @DataModel(format = DataModel.Format.MULTIPLE, path = "example.yml")
    public void order(MultipleModel model) {
        apiClient.doHttp("login") //调用yaml中name为 login的接口
                .processorByExpr("token", RedisDelProcessorCallback.class) //调用完做一些处理
                .eqByPath("${result}", 0) //断言
                .saveMethod("token", "token")  //保存作用域为method的缓存
                .onFailure(CancelFailHandle.class)  //如果失败执行失败兜底处理
                .done();// 结束

        apiClient.doHttp("index").auto();
    }

3.4 testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<!--tests级别:不同test tag下的用例可以在不同的线程执行,相同test tag下的用例只能在同一个线程中执行。-->
<!--classs级别:不同class tag下的用例可以在不同的线程执行,相同class tag下的用例只能在同一个线程中执行。-->
<!--methods级别:所有用例都可以在不同的线程去执行。-->
<!--thread-count: 并发线程数-->
<suite name="自动化">
    <test verbose="5" name="example" >
        <groups>
            <!--groups分组-->
            <define name="test">
                <include name="example" />
            </define>

            <!--运行的groups-->
            <run>
                <include name="test" />
            </run>
        </groups>
        <classes>
            <class name="com.example.ExampleApiTestCase" />
        </classes>
    </test>
</suite>

3.5 测试报告 (随便搞了个)

4.写在最后

如果小伙伴有兴趣的话我把业务代码清理下,开源, 源码大概 1w 多行吧,里面各种其他处理,也希望能收到各位宝贵的意见和建议

5. 开源地址

https://github.com/luoylove/api-test
by. 12.17

最佳回复
共收到 41 条回复 时间 点赞

感觉楼主这套思想设计挺不错的,但是想问一下,环境是如何管理的,不同环境主机地址和端口不一样,但是我看到 baseUrl 都是固定的

luoy #2 · 2020年12月16日 Author
cheunghr 回复

通过兼容 spring 的环境管理来进行管理 application 文件区分

  1. maven 运行时候通过 spring:profiles:active: #env# 来控制环境, mvn clean test -P uat -Dtestng.xmlFilePath=testng.xml, 通过-P 指定, 可集成 jenkins
  2. 调试通过@SpringBootTest注解控制环境, @SpringBootTest(properties = {"spring.profiles.active=uat"})
  3. baseUrl 一般写法都是会参数化的 ${base.url} 指向 application 文件

对框架的应用很合理,对注解的使用也很 6
如果不嫌烦,上一套 nacos 来切分管理环境配置也不错

楼主觉得 rest-assure 这种如何

luoy #5 · 2020年12月16日 Author
槽神 回复

我们公司的配置中心用的 apollo,是可以接入 apollo 管理环境的,但是觉得太麻烦,用 springboot 的环境切分就足够满足需求了

luoy #6 · 2020年12月16日 Author

rest-assure 基本能满足所有测试 api 的需求吧, 而且还提供了各种 listener 以供拓展, 感觉我用下来唯一的缺点就是源码很多用 groovy 写的, 遇到问题看源码看的头疼

luoy 回复

apollo 实在太重太繁琐了,nacos 开箱即用很方便,不过有一个缺点,那就是它是阿里开源😂
用配置中心的好处是可以把自动化测试接入到 CI/CD 的 pipeline 里面,一组配置端到端管到底,而不是中间断一下

接口自动化 我理解为有两种方式 一个是平台直接通过 swagger 导入所有的接口 然后业务根据场景将业务组合在一起 单接口根据接口的类型验证去自动生成异常数据验证单接口功能,正常的数据根据开发提测时的数据去验证 幂等的可以直接在平台上进行压力测试 ,这种的测试用例就是业务的业务场景。 还有一种就是楼主说的自己根据接口去手动编写一个个用例 然后执行。 这两种方式到底那种更加方便快捷呢

mark,我也准备搞一个类似的。之前写的感觉太重了。

luoy #10 · 2020年12月16日 Author
槽神 回复

其实直接 springboot 的环境支持就支持 jenkins 的 pipeline, 因为运行是 mvn clean test -P uat -Dtestng.xmlFilePath=testng.xml
是通过指定-P 来指定读取的配置文件, 在 jenkins 定义一个变量选择环境的配置文件, 然后-P 里面调用变量就行,这样就可以动态选择环境

luoy #11 · 2020年12月16日 Author
咸鱼菜鸡 回复

这个可以有,我准备实现下 swagger 抓取接口,生成 yaml 单接口测试文件,然后就可以根据生成的单接口组合用例流测试了

厉害,期待开源,哈哈😀 😀

让我想起来了 httprunner,有点像哦😂

期待开源哈,我最近也在思考类似的框架,不过是用 restAssured 替代 HTTPclient

如果是面试,我会问
推广使用的效果怎么样
如何说服测试同学放弃 postman,jmeter 这些工具
平台上有多少用例在跑,在 CICD 中发挥了什么作用

我用 JAVA+MYSQL+Httpclient+TestNG+Extentreports 也尝试过,但没弄出效果😂 。期待开源👍

luoy 回复

我也觉得单接口自动根据必要参数的数目,类型自动生成用例去测试比较好

luoy #18 · 2020年12月17日 Author
闲云野鹤 回复

之前设计的时候有参考过 httpruner

仅楼主可见
luoy #20 · 2020年12月17日 Author
MarvinWu 回复

推广方面基本上公司需要回归的主要业务接口都接入了,稳定性方面还是可以的
postman 我理解是适合做新接口调试, 不适合做这些老接口的自动化回归, 有短板,有需要访问第三方中间件的时候我能想到的解决方案是我再写一个代理系统与第三方中间件通讯,然后开放 http 接口给 postman 调用
jmeter 确实很好用,感觉有点重
如果用我这套解决方案,从写用例来说其实难度不是特别大,即使没有代码基础的,另外当你写多了的时候总会遇到问题,然后会去翻源码,会去找找解决方案,这个时候也是一个学习的过程,等要换工作了也能说说
CI/CD 方面来说,这要看各个公司的一些尺度了,有些是项目重构就自动触发执行一次接口测试,有些是只有到最后的回归了才总体执行一次,还有一些可能类似线上巡检接口的,需要定时执行

手动点赞👍 楼主有没有碰到这个问题。。 Allure 报告里记录条数过多(1000 条左右)就卡的不行啊,后面就只能选择把结果记录到数据库里了。 还有就是这个框架怎么和前端结合 (权限控制、测试触发、展示等功能) 成为一个测试平台呢?

这个是自己用,还是推广给其他人一起用了,反馈怎么样?

感谢作者开源,抓紧学习学习😀 😀

luoy #25 · 2020年12月18日 Author
Mr_Peace 回复

3000+ 用例都没问题啊,调调 allure 的启动参数? 调调内存什么的,或者优化用例,堆栈信息只显示 message 等等优化下
第二个问题我感觉你思想出问题了😂 ,为什么不从源头解决问题呢,权限控制为什么不做到用例运行级别,比如每一块业务接口生成一个 allure 报告,如果硬是要纠结从 allure 上解决问题,我记得 allure 的数据结构是根据 uuid 与 parent 的 uuid 关联,然后保存 json 文件,我觉得可在运行期间记录 uuid,然后根据你的权限规则生成 allure 的 json 文件,可行?

MarvinWu 回复

他若回答你已经有 2000+ 用例在跑了呢?

这个支持接口关联参数数据化吗,主要是上下游关联参数数据管理,还要初始化数据获取,哪些的公共数据,哪些是自定义数据,哪些是基础库数据,还要多数据源的管理,现在微服务接口链路复杂,需要支持 mock,接口监控能力,之前搞过放弃了,难。。。

luoy #28 · 2020年12月19日 Author

接口关联参数数据化, 这个我的实现是提供了多维度的数据保存模式,比如 saveMethod, saveClass,SaveThread,saveGlobal 等
多数据源可完全依靠 spring 的多数据源实现 每个数据源定义一个 beanName,注入的时候根据 beanName 注入即可
mock 和监控问题,这个怎么说呢 按我的理解这个属于一个测试环,而接口测试只是这一个环中的一块, 实现 mock 可以自建一个 mock 系统,至于监控 我觉得现在微服务情况下,即使测试环境也可上 skywalking 或者 pingpoint 等监控软件

大佬请教下你们接口用例一般怎么写呢,是单个接口 + 不同参数组合吗, 还是一条用例对应一个完整的功能流程(比如打开某个页面下单)

luoy #30 · 2020年12月22日 Author
单数 回复

都写,针对单接口的用例和业务流类型的用例

好奇问下,撸一个这样自动化框架到 V1.0 版本,耗时要多久

从 swagger 获取接口的请求参数这个我正在搞,但搞半天没搞透,swagger Json 太复杂,情况太多了,期望楼主搞完可以分享下。

luoy #33 · 2020年12月22日 Author
Nick 回复

这东西是边搞边优化,主要是看哪用的不爽了,就拓展下的

luoy #34 · 2020年12月22日 Author
redbiscuit 回复

swagger-parser 包了解下

不错不错,难得看到这么好的东西,之前也做过类似的东西,一开始也用 yml,但是解析 ${} 变量,是自己写的,感觉不太好用,后来改成 json 了,扩展相对方便些。
在报告里面,存结果的时候,可以修改一下结果的顺序,allure 默认是按字符串排序的,所以会变成 1 , 10,2 这样子,我是在它的前面补 0 的, 结果就按顺序排了 001, 002 ... 010 这样

仅楼主可见

您好,使用 yml 文件那如何生成随机数据入参呢

仅楼主可见
仅楼主可见

大佬弄个视频讲解一下呗

膜拜大佬 这下有学习资料了

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册