Skip to content

Latest commit

 

History

History
175 lines (142 loc) · 3.75 KB

一个最基本的测试结构.md

File metadata and controls

175 lines (142 loc) · 3.75 KB

基本目录结构

listen
├─ e2e
│  ├─ xxx.spec.ts
│  └─ xxx.spec.ts
└─ src
   ├─ app.controller.ts
   ├─ app.module.ts
   └─ app.service.ts
  • src/app.service.ts

    import { Injectable } from '@nestjs/common'
    
    @Injectable()
    export class AppService {
      sayHello(): string {
        return 'Hello World!'
      }
    }
  • src/app.controller.ts

    import { Controller, Get } from '@nestjs/common'
    // eslint-disable-next-line @typescript-eslint/consistent-type-imports
    import { AppService } from './app.service'
    
    @Controller()
    export class AppController {
      constructor(private readonly appService: AppService) {}
    
      @Get()
      getHello(): string {
        return this.appService.sayHello()
      }
    }
  • src/app.module.ts

    import { Module } from '@nestjs/common'
    import { AppController } from './app.controller'
    import { AppService } from './app.service'
    
    @Module({
      controllers: [AppController],
      providers: [AppService]
    })
    export class AppModule {}
  • e2e/xxx.spec.ts

    import type { TestingModule } from '@nestjs/testing'
    import { Test } from '@nestjs/testing'
    import { expect } from 'chai'
    import { AppModule } from '../src/app.module'
    import type { INestApplication } from '@nestjs/common'
    
    describe('...', () => {
      let testModule: TestingModule
      let app: INestApplication
      let server
    
      beforeEach(async () => {
        testModule = await Test.createTestingModule({
          // 切入点 1
          imports: [AppModule]
        }).compile()
        // 切入点 2
        // 可以下沉到 it() 中
        app = testModule.createNestApplication()
        // 可以下沉到 it() 中
        server = app.getHttpServer()
        await app.init()
    
        // 切入点 4,模拟发起多次请求以便在 it 中判断结果
      })
    
      afterEach(async () => {
        await app.close()
      })
    
      it('...', async () => {
        // 切入点 3
      })
    
      it('...', async () => {
        // TODO
      })
    })

切入点 1

切入点 2

可以指定不同底层 http 适配框架

import { ExpressAdapter } from '@nestjs/platform-express'
import * as express from 'express'
app = testModule.createNestApplication(new ExpressAdapter(express))
// 或
import { FastifyAdapter } from '@nestjs/platform-fastify'
app = testModule.createNestApplication(new FastifyAdapter())

切入点 3

// 1. 使用 supertest 模拟发起请求并使用 jest 内置断言判断
await request(server).get('/').expect(200)
// 或
await request(server).get('/').expect(200, {
  /* response body data*/
})
await request(server).get('/notfound').expect(404)

// 2. expect 可以多次使用
const response = await request(server).get('/').expect(200)
// chai
expect(response.body.title).to.equal('My Website')

// 3. expect 中可以是函数
request(server)
  .post('/cats')
  .send(cat)
  .expect(201)
  .expect(({ body }) => body.name === cat.name)

// 4. 可以进行相关配置
app.setLocal('title', 'My Website')
app.setGlobalPrefix('/api')

// 5. 可以使用 chai 库提供的断言
expect(await app.getUrl()).to.be.eql(`http://127.0.0.1:3000`)

// 5. 可以以 try catch 方式测试异常情况
try {
  await app.getUrl()
} catch (err) {
  expect(err).to.be.eql(
    'app.listen() needs to be called before calling app.getUrl()'
  )
}

切入点 4

const performHttpCall = end => {
  request(server)
    .get('/hello')
    .end((err, res) => {
      if (err) return end(err)
      end()
    })
}
await new Promise(resolve => performHttpCall(resolve))
await new Promise(resolve => performHttpCall(resolve))
await new Promise(resolve => performHttpCall(resolve))

it(`should create controller for each request`, async () => {
  expect(HelloController.COUNTER).to.be.eql(3)
})