关于如何使用Gitlab CI搭建NestJS单元测试自动化体系

505 阅读3分钟

单元测试是为了提高代码的质量规范代码,单元测试不仅可以保证当前代码的正确性,也能保证在持续迭代的过程中保证代码的正确性

实现自动化的目标

  • 实现项目的单元测试覆盖率目标
  • gitlab ci和单元测试结合
  • 可视化单元测试报告

要实现以上目标,需要大致了解gitlab相关知识和jest测试框架的基本使用。

方案

image.png

方案一

  • 完成本地代码修改 - 修改业务代码
  • 代码提交Gitlab -  通将修改好的代码通过git命令提交到仓库
  • 触发Gitlab CI - 通过gitlab-ci.yml配置CI脚本,触发相对应的job。并执行脚本
  • 执行测试脚本 - CI在执行脚本的过程中,执行项目中的测试命令
  • 可视化测试覆盖率 - 将测试结果展示在Homepage上

方案二

  • 完成本地代码修改 - 修改业务代码
  • 代码提交Gitlab -  通将修改好的代码通过git命令提交到仓库
  • 通过Git Hook触发测试脚本 - 通过husky配置当代码在本地进行提交的过程中,执行test ci脚本
  • 代码上传 - 提交代码致仓库
  • 通过Gitlab Page可视化单侧结果 - 配置gitlab setting配置静态网站展示执行单侧结果

由于方案二的一定局限性,所以选择方案一:

  1. 方案二在开发过程中,由于切换分支会进行暂时commit 操作,导致执行单侧,不是目标策略。
  2. 方案二代码会提交单侧报告,代码冗余
  3. 方案二由于gitlab权限问题,没有page设置权限,无法进行静态资源展示配置
  4. 方案一具有分支控制优势,可配置仅在master分支改动时执行单元测试

依赖

当前主要依赖于jest和jest-junit,进行单侧编辑时,需要依赖@types/jest

版本备注
jest^27.2.5Complete and ready to set-up JavaScript testing solution
jest-junit^13.0.0A Jest reporter that creates compatible junit xml files

使用

依赖测试框架实现测试用例。

代码示例如下:

import { Test, TestingModule } from '@nestjs/testing'
import { Module } from './*.module'
import { Service } from './*.service'

describe('Service', () => {
  let service: Service

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [Module]
    }).compile()

    service = module.get<Service>(Service)
  })

  describe('checkPermission', () => {
    it('checkPermission', async () => {
      // 业务代码
    })
  })

})

配置

目前配置主要分为两个部分

  • jest 相关配置
  • gitlab ci相关配置
  • gitlab 配置

jest配置

jest test脚本执行规则。

比较重要的几个参数:

  • 文件匹配: testRegex
  • 别名映射: moduleNameMapper
  • 输出目录: coverageDirectory
  • 报告文件: coverageReporters
 "jest": {
    "moduleFileExtensions": [
      "ts",
      "js",
      "json",
      "node"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "moduleNameMapper": {
      "^@/(.*)$": "<rootDir>/src/$1"
    },
    "collectCoverage": true,
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "coverageReporters": [
      "cobertura",
      "text",
      "html",
      "text-summary"
    ],
    "testEnvironment": "node",
    "coverageThreshold": {
      "global": {
        "statements": 80
      }
    }
  },

gitlab-ci.yml配置

主要目的是触发gitlab CI pipeline

这部分使用到gitlab ci相关配置项,建议阅读官方文档docs.gitlab.com/ee/ci/yaml/…

image: node:12-slim

# CI_MERGE_REQUEST_TARGET_BRANCH_NAME 合并请求的目标分支名称。
# CI_MERGE_REQUEST_SOURCE_BRANCH_NAME 合并请求的源分支名称
# CI_COMMIT_BRANCH 提交分支名称。在分支管道中可用,包括默认分支的管道。在合并请求管道或标签管道中不可用。

stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - yarn
  cache:
    paths:
      - node_modules/
  artifacts:
    expire_in: 1 days
    when: on_success
    paths:
      - node_modules/

test:
  stage: test
  coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
  allow_failure: true
  dependencies:
    - build
  script:
    - npm run test:ci
  cache:
    paths:
      - coverage/
  artifacts:
    when: always
    reports:
      junit:
        - junit.xml
      cobertura: coverage/cobertura-coverage.xml

pages:
  stage: deploy
  dependencies:
    - test
  script:
    - mkdir .public
    - cp -r coverage/* .public
    - - mv .public public
  artifacts:
    paths:
      - public
  only:
    - master


gitlab 配置

主要目的是为了让单元测试覆盖率可视化

大致流程

image.png

gitlab展示

image.png

找到Test coverage parsing 配置项,输入以下字符

Lines\s*:\s*(\d+.?\d*)%

创建自定义Badges

image.png 根据提示自定义pipelines 图标和coverage图标

image.png

配置Readme.md

在readme.md加上配置好的图标,这里可以参考配置项的地址

[![coverage report](https://example.gitlab.com/%{project_path}/badges/%{default_branch}/coverage.svg)](https://example.gitlab.com/%{project_path}/-/commits/feat-v1.0.0)

最终我们可以得到以下展示:

image.png

image.png

命令

执行test:ci脚本

"test:ci"`` :  ``"jest --config ./jest.config.js --collectCoverage --coverageDirectory="./coverage" --ci --reporters=default --reporters=jest-junit --watchAll=false"

结束语

2022.2.11

木更