单元测试:一个能确保输出想要结果的小天使

发表于:2020-12-10 10:12

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:小蘑菇糖糖    来源:知乎

  为何要写单测
  单元测试(Unit Test)作为持续集成实现中的一环,位于金字塔模型的底部,目标是证明代码的某个单元(被测试的主体)能按照预期工作,这样我们在开发过程早期就能发现问题。
  一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
  说白话,就是确保你代码输出的是你想要的结果。
  直接来看个例子。
  项目使用了MomentJS处理时间相关的Case,前阵子Moment.js 宣布停止开发,进入维护状态,加上又有打包体积的优化需求,Day.js无疑是更好的选择,遂进行替换。
  两者API基本相同,但某些Case下还是略有不同,比如:
  // 返回某年第几周的首尾日期(MM/DD)
  function transforWeekInterval(year, weekNums = 1) {
    const now = moment(year);
    // 这里有一些边界的校验,略过...
    now.add(weekNums - 1, 'w');
    return {
      start: now.startOf('isoWeek').format('MM/DD'),
      end: now.endOf('isoWeek').format('MM/DD')
    }
  }
  // output: transforWeekInterval('2020') -> {end: "01/05", start: "12/30"}
  针对这个函数有以下测试用例
  // Test Case 0
  it('should transforWeekInterval return correct value in 2021 w10', () => {
    expect(transforWeekInterval('2021', 10)).toEqual({end: "03/07", start: "03/01"});
  });
  // Test Case 1
  it('should transforWeekInterval return correct value in the first week 2020', () => {
    expect(transforWeekInterval('2020')).toEqual({end: "01/05", start: "12/30"});
  });
  当简单地将moment替换成day.js后,发现测试用例Case 1未通过,
  expected: {end: "01/05", start: "12/30"}
  received: {end: "01/01", start: "01/01"}
  // 这里的修复
  // dayjs().startOf('isoWeek') -> dayjs().isoWeekday(weekNums -1)
  如此,重构早期便可以发现错误,及时处理,否则在后面的测试环节需要投入更多的人力。也一定程度说明了单测的重要性,放心重构。
  配置
  Jest 是由 Facebook 维护的 JavaScript 测试框架,其重点是简单性。它适用于以下項目:Babel、TypeScript、Node.js、React、Angular 和Vue.js。
  为什么使用Jest,不赘述,简单易用、代码覆盖率,也有比较清晰的报错信息。这里给到一份React项目常用的配置,对应的配置项在文档中可找到说明。
  // In package.json
  "jest": {
      // 测试入口
      "roots": [
        "<rootDir>/src"
      ],
      // 覆盖率收集
      "collectCoverageFrom": [
        "src/**/*.{js,jsx}",
      ],
      // 初始化的一些配置,路径数组
      // 在jest inital之前执行,比setupFilesAfterEnv更早,例如可以设置全局变量到global
      "setupFiles": [
        // jsdom,不涉及dom可不引入
        "react-app-polyfill/jsdom"
      ],
      // 类似,在jest inital之后执行,这一步能拿到jest的api进行扩展(故名AfterEnv)
      // 可以执行例如引入enzyme配置等
      "setupFilesAfterEnv": [
        "<rootDir>/src/setupTests.js"
      ],
      // 测试匹配文件
      "testMatch": [
        "<rootDir>/src/**/__tests__/**/*.{spec,test}.{js,jsx}",
        "<rootDir>/src/**/*.{spec,test}.{js,jsx}"
      ],
      "testEnvironment": "jest-environment-jsdom-fourteen",
      // 转译, babel插件引入
      "transform": {
        "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
        "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
        "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
      },
      "transformIgnorePatterns": [
        "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
        "^.+\\.module\\.(css|sass|scss)$"
      ],
      "modulePaths": [],
      "moduleNameMapper": {
        "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",
        // alias, 与Webpack一致
        "@images(.*)$": "<rootDir>/src/images/$1",
        "@components(.*)$": "<rootDir>/src/components/$1",
        "@utils(.*)$": "<rootDir>/src/utils/$1",
        "@service(.*)$": "<rootDir>/src/service/$1"
      },
      "modulePathIgnorePatterns": [
        // test 中使用的mock文件,可忽略
        "__mocks__"
      ],
      "moduleFileExtensions": [
        "web.js",
        "js",
        "json",
        "web.jsx",
        "jsx",
        "node"
      ]
    }
  以上是JavaScript的配置,配置的目录结构测试文件位于src/**__tests__/,好处是贴近业务代码,也可以统一维护在根目录的test目录下。TS也差不多。可见配置上简单易懂,基本上可以说是开箱即用了。
  Jest配置可以单独维护在具体的文件中,然后在cli中指定,也可以放在package.json。React的create-react-app则提供了开箱即用的jest配置和example。略微有坑点可能是Babel转译这块,Jest 无法直接解析 JSX 的语法,好在常见的错误都可以搜索得到。
  代码覆盖率
  覆盖率的意义在于分析未覆盖部分的代码,从而反推在前期测试设计是否充分,没有覆盖到的代码是否是测试设计的盲点。一般地,也作为测试考核的一个节点,但不应该成为重点。第二一个是增量覆盖率,可以使用istanbul.js等来统计。
  在Jest cli中添加--coverage即可生成代码覆盖率报告,或者在配置文件中设置collectCoverage: true。
  运行测试完毕后结果如下:
  同时也会在根目录下生成coverage目录,里面是可视化的web文件,具体到覆盖行/分支,也有代码视图:
  开发中要实现比较完好的单测覆盖,目测会增加20%-30%的开发量,所以需求评估时注意多给点时间...
  个人理解测试既能保障产品交付,也可以提升代码质量,编写可测试代码应该是基本能力。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号