疑问

书摘&心得

写开源插件的话,绕不开单元测试的编写

babel-plugin-tester

借助工具已经很完善了,相当于单纯的字符串比较,结果是否符合:

  1. import pluginTester from 'babel-plugin-tester';
  2. import xxxPlugin from '../xxx-plugin';
  3. pluginTester({
  4. plugin: xxxPlugin,
  5. fixtures: path.join(__dirname, '__fixtures__'), // 保存测试点的地方
  6. tests: {
  7. 'case1:xxxxxx': '"hello";', // 输入输出都是同个字符串
  8. 'case2:xxxxxx': { // 指定输入输出的字符串
  9. code: 'var hello = "hi";',
  10. output: 'var olleh = "hi";',
  11. },
  12. 'case3:xxxxxx': { // 指定输入输出的文件,和真实输出对比
  13. fixture: 'changed.js',
  14. outputFixture: 'changed-output.js',
  15. },
  16. 'case4:xxxxxx': { // 指定输入字符串,输出到快照文件中,对比测试
  17. code: `
  18. function sayHi(person) {
  19. return 'Hello ' + person + '!'
  20. }
  21. `,
  22. snapshot: true,
  23. },
  24. },
  25. });

dumi的api-parser单元测试的思想

https://github.com/umijs/dumi/blob/master/packages/preset-dumi/src/api-parser/index.test.ts
测试文件:
具体代码不重要,主要的思想是读取原文件,用待测试函数转换后生成一个结果,比较与预期结果是否符合:

  1. function assertResult(filename, extraProperties?) {
  2. expect(winEOL(JSON.stringify(parser(path.join(rawPath, filename), extraProperties), null, 2))).toEqual(
  3. winEOL(
  4. fs
  5. .readFileSync(path.join(expectPath, `${path.basename(filename, '.tsx')}.json`), 'utf8')
  6. .toString(),
  7. ),
  8. );
  9. }
  10. describe('api parser', () => {
  11. it('should parse with skipNodeModules', () => {
  12. assertResult('skipNodeModules.tsx', {
  13. skipNodeModules: true,
  14. });
  15. });
  16. });

源文件skipNodeModules.tsx

  1. // skipNodeModules.tsx
  2. import React from 'react';
  3. import type { Node } from 'unist';
  4. export interface IAextendsNodeProps extends Node {
  5. /**
  6. * extra CSS className for this component
  7. */
  8. className?: string;
  9. /**
  10. * inline styles
  11. */
  12. style?: React.CSSProperties;
  13. /**
  14. * component size
  15. * @default small
  16. */
  17. size: 'small' | 'large';
  18. }
  19. // eslint-disable-next-line react/prefer-stateless-function
  20. class AextendsNode extends React.Component<IAextendsNodeProps> {
  21. render() {
  22. return <>Hello World!</>
  23. }
  24. }
  25. export default AextendsNode;

结果skipNodeModules.json

  1. // skipNodeModules.json
  2. {
  3. "AextendsNode": [
  4. {
  5. "identifier": "className",
  6. "description": "extra CSS className for this component",
  7. "type": "string"
  8. },
  9. {
  10. "identifier": "style",
  11. "description": "inline styles",
  12. "type": "CSSProperties"
  13. },
  14. {
  15. "identifier": "size",
  16. "description": "component size",
  17. "type": "\"small\" | \"large\"",
  18. "default": "small",
  19. "required": true
  20. }
  21. ]
  22. }

可以看到编译原理的测试是非常灵活的,借助已有工具库可以完成纯字符串转换的比较,当比较涉及的文件类型、转换思路、转换目标发生改变时,只要按照主要思路进行方案调整即可,在测试的过程中,思路>>>方法。

babel插件单元测试的主要思路就是写一段目标代码,再写一份目标代码,转换后比较结果是否符合预期即可。