Uninote
Uninote
用户根目录

powder backend docs

user configs: https://docs.uninote.com.cn/book/1/2257#353472986F

开发环境搭建

初始安装项目到本地

git clone git@git.dajxyl.com:cyb/powder.git
cd powder
git checkout dajx
npm install
cd src\powder && npm install

运行服务

cd 项目根目录
npm run serve
# 示例访问地址(这些参数 dev 服有效):http://localhost:8080/?phone=13320817857&staff_id=62&phone_staff=13778707887&passwd_staff=123456

项目结构

  • /api: 接口文档存放处
  • /powder/generated: 根据 /api 自动生成的代码,不要手动修改
  • /powder/user: 根据 /api 自动生成的模板代码,在此基础上编写生成函数、测试代码等
  • /tests - 测试相关的公共模块存放处

开发流程

整个接口的开发流程就是不断的重复以下三个步骤。

API: code as doc

https://docs.uninote.com.cn/book/1/2374#48E64A965B

代码生成

  • cd src\powder
  • node generate.js
  • 如果有冲突,会自动调起 beyond compare 解决冲突,完成后再执行 node generate -r(自动更新 base 文件,类似于 git add xx,并清理临时文件)**
    • 需要将 beyond compare 加入 PATH 环境变量
    • 当然也可以手动解决冲突,但强烈不建议!
  • 注:可以使用 node generate.js -w,开启监控模式,文件更新后会自动重新生成代码,这一步不再需要每次手动执行。按 ctrl + c 退出监控模式。
  • node generate 会进行时间戳比较,只有当 api 下的文件比 user 下对应的文件更新时,才会执行生成;如要强制执行,可以加 -f 参数

解决冲突

http://v.uninote.com.cn/video_play.html?video_url=http://admin.bb.uninote.com.cn/oss?path=video/upload/202110/20211018_161216.mp4

原理

http://v.uninote.com.cn/video_play.html?video_url=http://admin.bb.uninote.com.cn/oss?path=video/upload/202110/20211018_162010.mp4

tips

http://v.uninote.com.cn/video_play.html?video_url=http://admin.bb.uninote.com.cn/oss?path=video/upload/202110/20211018_162433.mp4

如果对冲突解决是否正确没有把握,可以进行多次比对确认:

  • x.js.base -- x.js.new,必要时手动将变更添加到 x.js
  • x.js.new -- x.js: 确认是否基于模板正确修改
  • 执行 node generate -r
  • old x.js -- x.js 确认之前的手动修改是否丢失

编写生成函数、测试代码等 (user/*):

user 规范详解:https://docs.uninote.com.cn/book/1/2257#353472986F

  • 配置 default 参数
  • 编写 gene args 生成逻辑
  • 调通接口
  • 编写单元测试

生成函数 - core of powder

对象组成结构

假设 api 下有一个模块 test.js,则生成代码后的对象组成结构为:

user/test.js -> generated/test.js -> base(base.js)
   |--> api/test.js
  • 尽可能的使用封装对象,当然必要时仍然可以直接调用原始 api

使用场景

当做 postman 使用时(前端开发人员)

查看接口时,一键生成参数,就能保证接口请求成功

当前接口开发时

编写/演示 必要的场景,eg:

这里相当于将自测的用列固化为测试代码(场景),以备后用(共享)

  • 自己
  • review
  • 测试
  • 前端开发人员
  • 批量测试
  • 被依赖

接口开发完成的标志就是,对于每一个场景,接口返回值验证单元测试都通过了(“请求-完整验证”不报错)。

被依赖时: base.make()

  • 接口开发使用自底向上,逐步积累的方式
  • 通过 base.make() 被调用(依赖)的接口,会进行接口返回值验证,但不会进行单元测试
    • 因为这里只需要保证被依赖的接口返回的数据符合预期即可

调试定位

这里 讲了两种线上定位方式,开发环境时,还可以通过 debugger 定位:

请求: base.request()

完整验证: base.fullValidate()

https://docs.uninote.com.cn/book/1/2257#DB817E0B31

生成函数的结果 - 生成值,会被常规流程使用一次,以及 testSuites 使用 0-n 次。

返回值验证

  • 状态码验证
  • 数据结构验证:验证当前的请求结果是否与接口的返回值注释匹配(仅比较结构)

单元测试

生成参数保存-还原:base.save() & base.restore()

便捷的生成参数保存-还原工具,用于保存一份有效的参数,后面每次在此基础上进行修改测试:

    ctx.generated = {
      id: 1,
      name: 'lucy',
    };
    ctx.save();
    ctx.generated.id = 2;
    console.log({...ctx.generated}); // {id: 2, name: 'lucy'}
    ctx.restore(); // 恢复上次保存的生成参数
    console.log({...ctx.generated}); // {id: 1, name: 'lucy'}

按照当前参数显式的调用接口:base.request2()

一般情况下,都是在生成函数中生成参数,再由框架负责调用接口,下面的实例中,则是在生成函数中循环生成参数-调用接口(cartAdd)。这里生成函数类型设置为 GENE_ONLY, 是为了生成函数调用后框架不会再次调用接口(cartAdd)。

'cartAdd': {
  '__proto__': base.cartAdd,
  'api': apis.cartAdd,
  'desc': " [商城模块]添加购物车",
  'geneArgs': [
    {
      'scene': 'product_sku_list',
      'desc': '添加商品SKU列表',
      'type': GENE_ONLY,
      'func': async (ctx) => {
        let shop_sku_id = (await infos.productSkuList.make()).data.data.info.productSku;
        for (let sku_id of shop_sku_id) {
          ctx.generated.product_sku_id = sku_id.id;
          await ctx.request2()
        }
      }
    }

快速错误定位

  • ReqIndex:request index,会为每一个请求生成一个索引,每次请求加1,页面刷新后重置为0。

    • network panel, request header 可以看到
    • 报错时可以得到出错的 ReqIndex:
    • 如果启用了 debug,则有如下输出:
  • TrackID:每个终端可以配置自己的 ID,当多终端并发测试时后台日志可以区分是哪个终端发送的请求

    • 配置 tid=1,建议在 local storage 全局配置
  • ReqIndex,TrackID在后台的日志中也会相应存在,可以方便查找对应的日志

  • 以上两点的前提是后台记录了请求参数信息

实例 & 技巧

// 缓存数据到 ctx 中以备后用:
ctx.__info = info;

// 直接调用依赖接口:
let data = (await infos.getExpressSelect.api(arg1, arg2)).data.data;

// 都通过 make 调用依赖接口,能够直接拿到返回值
let data = (await infos.getExpressSelect.make()).data.data;

// 祖先接口返回值获取:
// 1 模块内:
infos.create.lastResult.data
// 2 跨模块:
import * as shop_order from '../client/shop/order';
shop_order.infos.create.lastResult.data

  • 表情要用这种表示方式:

配置 webpack.alias.js:

  • 用 '@' 表示 'src',简化路径引用,eg:
import * as scms from '../../../tests/scms';
// 等价于上面的写法,但更简洁,同时文件移动位置后更易于维护
import * as scms from '@/tests/scms';

powder-api

powder-bugs

点赞(0) 阅读(1) 举报
目录
标题