0.0.1 • Published 5 years ago

utdsl v0.0.1

Weekly downloads
-
License
ISC
Repository
-
Last release
5 years ago
  • 为什么要使用TDSL

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

由于用例大部分都是验证单元模块IO验证验证,核心代码比较固定和机械化,那么完全可以根据源码进行ast分析,解析出各个模块的io类型,并重新构造,直接生成用例代码,我们只需要指令式声明IO样本数据即可。为此,这里定义了一套简洁的描述语法规则TDSL(Test DSL)。

  • TDSL引入的优势

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

优势: 1,不用手写用例代码,不用维护 2,从注释直观开发UT测试io,面向指令,所有用例一目了然 3,统一用例代码,使用核心语法,保持一致性 (其实完全不用关心) 4,约束函数实现,约束一个函数只做一件io事情,手动编写的用例过于灵活,后面维护成本比较高 5,大大降低TDD成本 6,注释文档、逻辑、用例同步更新,避免同步的成本 7,方便统一IO样本数据存放 8,提高效率的同时对源码的组织结构形成固定约束 9,覆盖率低?不存在的

劣势: 增加注释量

  • TDSL常用语法

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

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) => (returnValue)

/**
 * 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文件内容为(支持两种形式)

// 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);
});

稍微完整的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);
});
0.0.1

5 years ago