npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tdml

v0.0.4

Published

测试描述标记语言

Downloads

2

Readme

  TD(Test Description)ML, 测试描述标记语言,是一套用于高效简洁描述测试代码的规范语言。

  • 为什么要使用TDML

  单元测试是开发中重要的一部分工作之一,但是常常,业务时间紧张,除了要加用例代码,还要维护旧的用例,每个人用例写法多少也有不一致,同伴的用例代码也往往会含有特定逻辑,而且代码量大修改起来也难定位,前前后后也耗不少时间。不得不说,用例虽不难,但也会让我们投入不少精力。

  由于用例大部分都是验证单元模块IO验证验证,核心代码比较固定和机械化,那么可以根据源码进行ast分析,解析出各个模块的io类型,并重新构造,直接生成用例代码,我们只需要指令式管理IO样本数据即可。为此,这里定义了一套简洁的描述语法规则TDML(测试描述标记语法,Test Description ML)。TDML的基础理念是:同样的测试用例的代码只写需要工具一次,其他的交给TDML

  而至于底层使用mocha还是jest生成用例,可通过tdml.config.js配置。开发者只需要在注释中写指令语法就可以了。

  • TDML引入的优势

  所有语法必须写在函数前的块注释(/**/)中。然后自动生成对应的完整测试用例代码。

  优势:

1,不用手写用例代码,不用维护

2,从注释直观开发ut测试IO,面向指令,所有用例和模块IO一目了然。边界IO也更加直观

3,统一用例代码,使用核心语法,保持一致性 (其实完全不用关心)

4,约束源码实现,约束一个函数只做一件IO事情,手动编写的用例过于灵活,后面其它人维护成本较高

5,大大降低TDD成本

6,注释文档、逻辑、用例同步更新,避免同步的成本

7,统一IO数据样本文件管理,样本数据更易维护

8,提高效率的同时对源码的组织结构形成反向约束 (需要按照规范的方式写,才能自动生成用例)

9,覆盖率低?不存在的

  劣势: 增加注释量。

  • 安装使用
npm i tdml -g
tdml c [path] # 例如 tdml c ./src/code.js

  也可以安装在项目中书写tdml.config.js进行配置,并安装插件自动触发。

  • TDML常用语法

  为了不对源码进行入侵,也不额外维护文件,TDML使用注释语法规范。必须在块代码注释中声明,否则不生效,但也不产生任何影响。

1、判断相等

fn(...Params) => (returnValue),例如

/* name function B
 * this is test
 * B(1, 3) => (3)
 */
export function B (a: number, b: number): number {
    return a * b;
}

自动编译后

test("B module", () => {
    expect(B(1, 3)).toBe(3);
});
2、判断对象深度相等

fn(...Params) ==> (returnValue),例如

/* name B
 * this is test
 * B(1, 3) ==> (3)
 */
export function B (a: number, b: number): number {
    return a * b;
}

自动编译后

test("B module", () => {
    expect(B(1, 3)).toEqual(3);
});
3、判断对象不相等

fn(...Params) !=> (returnValue),例如

/* name B
 * this is test
 * B(1, 3) !=> (4)
 */
export function B (a: number, b: number): number {
    return a * b;
}

自动编译后

test("B module", () => {
    expect(B(1, 3)).not.toBe(4);
});
4、判断对象深度不相等

fn(...Params) !==> (returnValue),例如

/* name B
 * this is test
 * B(1, 3) !==> (4)
 */
export function B (a: number, b: number): number {
    return a * b;
}

自动编译后

test("B module", () => {
    expect(B(1, 3)).not.toEqual(4);
});
5,路径常量数据文件

使用冒号分割,冒号前为读取mock数据的属性key,后面为相对路径,带不带引号都可以,重复路径最终会自动合并

(:path, data.dataKey: path, ...params) => (data.dataKey: path)

/**
 * name B
 * A(a: './data.js', 3) => (3)
 * A(b:./data.js, d:"./data1.js") => (1)
 * A(a:./data.js, 1) => (a.b:./data1.js)
 */
export function B (a: number, b: number): number {
    return a * b;
}

其中data.js和data1.js文件内容为(支持export和module.exports导出)

// data.js
module.exports = {
    a: 1,
    b: 1
};

// data1.js
export default {
    c: 1,
    d: 1
}

自动编译后

const data1 = {
    a: 1,
    b: 1
};
const data2 = {
    c: 1,
    d: 1
}
test("B module", () => {
    expect(B(data1.a, 3)).toBe(3);
    export(B(data1.b, data2.d)).toBe(1);
    export(B(data1.a, 1)).toBe(data2.d);
});
6, 属性判断

fn(...Params).property => (lengthValue),例如

/* name B
 * this is test
 * B(1, 3).length => (1)
 * B(1, 3)['length'] => (1)
 * B(1, 3)['length']['xxx'] !=> (1)
 */
export function B (a: number, b: number): number {
    return a * b;
}

自动编译后

test("B module", () => {
    expect(B(1, 3).length).toBe(1);
    expect(B(1, 3)['length']).toBe(1);
    expect(B(1, 3)['length']['xxx']).not.toBe(1);
});

7,异步链式判断

fn(...params) -> (module1) ==> (returnValue)

  异步执行fn,然后判断module1的值是否和returnValue相符。

/**
 * 拉取按天时间段报表,内部操作为拉取一个接口,然后把接口数据dispatch到store上
 *
 * getOverviewChart({}, {}) -> (getState().apiData) ==> ({chart: {a:1}})
 */
export const getOverviewChart = (params = {}, options = {}) => (dispatch, getState) => {}

  编译后,这里需要配置tdml.config.js来决定是否使用dispatch

dispatch(getOverviewChart({}, {})).then(() => {
  expect(getState().apiData).toEqual({
    chart: {
      a: 1
    }
  });
  done();
}, () => {});

8,链式触发调用和断言

fn(...params) -> number1(module1:path) -> ... -> number2(module2:path) => (returnValue)

  fn调用时调用module1次数为number1,调用module2次数为number1,然后返回断言值为return

稍微完整的examples
/**
 * add(6, 3) !=> (4)
 * add(2, 3) ==> (6)
 * add(2, "3") !=> ("13")
 * add("abc", "df") => ("abcdf")
 * add(path.b: './data/data', "df") => ("abcdf")
 * add(:./data/data)['length']['xx'] => (234)
 * add(b.c:'./data/data1').length => (123)
 * add(b.c:./data/data1).length => (b.c: ./data/data3.js)
 */
export function add (a: number, b: number): number {
    return a + b;
}

编译后

const data3 = {
  "b": {
    "c": 4
  }
};
const data2 = {
  "data": [1, "kesd", 3, "oooo", {
    "a": 1
  }, {
    "a": 1,
    "b": 2,
    "c": {
      "a": 1,
      "b": 2,
      "c": [{
        "a": 1,
        "b": 2
      }]
    }
  }],
  "path": "mmmmmmmmmmmmm"
};
const data1 = {
  "data": [1, "kesd", 3, "oooo", {
    "a": 1
  }, {
    "a": 1,
    "b": 2,
    "c": {
      "a": 1,
      "b": 2,
      "c": [{
        "a": 1,
        "b": 2
      }]
    }
  }],
  "path": "mmmmmmmmmmmmm"
};
test("add module", () => {
  expect(add(6, 3)).not.toBe(4);
  expect(add(2, 3)).toEqual(6);
  expect(add(2, "3")).not.toBe("13");
  expect(add("abc", "df")).toBe("abcdf");
  expect(add(data1.path.b, "df")).toBe("abcdf");
  expect(add(data1)['length']['xx']).toBe(234);
  expect(add(data2.b.c).length).toBe(123);
  expect(add(data2.b.c).length).toBe(data3.b.c);
});

TODO:

1, 文件依赖自动解析

2, react集成配置解析 tdml.config.js

3,redux 集成配置解析 tdml.config.js

4,自动插件化 tdml.config.js

5,数据转换类模块用例分析(测试验证函数IO是否符合预期) 已完成

6,请求数据并dispatch数据类型模块分析(Mock接口数据,验证dispatch后对应节点数据是否符合预期)

7,ui事件触发类型函数分析(事件模拟,判断是否调用对应的其它模块以及调用的次数)

8,ui渲染类节点特性判断(渲染,然后节点查询对应的节点)

FUTURE TODO:

//