启动单元测试
zengwe$ npm run test
运行效果
PASS src/admin/controllers/zeng-Try.controller.spec.ts
Test Suites: 1 skipped, 14 passed, 14 of 15 total
Tests: 7 skipped, 57 passed, 64 total
Snapshots: 0 total
Time: 7.422s, estimated 10s
Ran all test suites related to changed files.
Watch Usage: Press w to show more.
controller单元测试
import { Body, Controller, Post, Get, Put, Delete, Query } from '@nestjs/common';
import { isNullOrUndefined } from 'util';
import { code } from '../../common/code';
import { zengTryService } from '../services/zeng-Try.service';
import { AddForm, UpdateForm, DeleteForm} from './zeng-Try.form';
import { ValidationPipe } from '../../pipes/validation.pipe';
@Controller({
path: '/api/zeng/Try'
})
export class zengTryController {
constructor(protected zengTrySrv: zengTryService) {
}
@Get('/all')
async getAll() {
let list = await this.zengTrySrv.getAll();
return {code: code.success, data: {list: list}};
}
@Post()
async add(@Body(new ValidationPipe()) form: AddForm) {
let res = await this.zengTrySrv.addTry(form);
return {code: code.success, data: res};
}
@Put()
async update(@Body(new ValidationPipe()) form: UpdateForm) {
let res = await this.zengTrySrv.updateTry(form);
return {code: code.success, data: res};
}
@Delete()
async delete(@Query(new ValidationPipe()) form: DeleteForm) {
let res = await this.zengTrySrv.deleteTry(form.id);
return {code: code.success, data: res};
}
}
@Body(new ValidationPipe() 为表单验证的中间件不是单元测试的重点,反正表单不合格就返回对应错误
import { INestApplication, MiddlewareConsumer, Module, NestModule, Controller, Get, Post, Header, Session, Injectable, NestMiddleware, Logger, HttpException, HttpStatus } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { code } from '../../common/code';
import { zengTryController } from './zeng-Try.controller';
import { zengTryService } from '../services/zeng-Try.service';
import * as request from 'supertest';
const apiPrefix = '/api/admin/zeng/Try';
describe('zeng Try controller', () => {
let app: INestApplication;
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [],
controllers: [zengTryController],
providers: [
{
provide: zengTryService,
useValue: {
getAll: () => {
return Promise.resolve([]);
},
addTry: (data) => {
return Promise.resolve(data);
},
updateTry: () => {
return Promise.resolve({});
},
deleteTry: () => {
return Promise.resolve(null);
}
}
}
]
})
.compile();
app = module.createNestApplication();
await app.init();
});
it('get All', (done) => {
request(app.getHttpServer())
.get(apiPrefix+'/all')
.expect(200)
.end(function (err, res) {
expect(res.body.code).toEqual(code.success);
done();
});
});
it('add form error test', (done) => {
request(app.getHttpServer())
.post(apiPrefix)
.expect(200)
.end(function (err, res) {
expect(res.body.code).toEqual(code.formErr);
expect(Object.prototype.toString.call(res.body.data)).toEqual('[object Array]');
done();
});
});
it('add Try', (done) => {
request(app.getHttpServer())
.post(apiPrefix)
.send({
apiName: 'dd3',
alias: 'cc3s',
isVip: true,
isNormal: true,
isEducation: true,
isTest: true,
isPublic: true
})
.expect(201)
.end((err, res) => {
expect(res.body.code).toEqual(code.success);
expect(Object.prototype.toString.call(res.body.data)).toEqual('[object Object]');
done();
});
});
it('update Try no id', (done) => {
request(app.getHttpServer())
.put(apiPrefix)
.send({apiName: 'fdsafd'})
.expect(200)
.end((err, res) => {
expect(res.body.code).toEqual(code.formErr);
done();
})
});
it('update Try', (done) => {
request(app.getHttpServer())
.put(apiPrefix)
.send({apiName: 'fdsafd', id: 1})
.expect(200)
.end((err, res) => {
expect(res.body.code).toEqual(code.success);
done();
})
});
it('delete Try', (done) => {
request(app.getHttpServer())
.delete(apiPrefix)
.query({id: 1})
.expect(200)
.end((err, res) => {
expect(res.body.code).toEqual(code.success);
done();
})
});
});
createTestingModule相当于@Module()需要什么就添加什么。
it(string,function);中function是支持async/await的,done为可选参数
测试目标为仅仅这个controller,所以对于依赖的service用一个假的替换掉,认为这个service是完美的。至于service真实情况是否完美,那放到对应的service中去测试;
上面还缺少一个文件上传
it('upload', async (done) => {
let fileStre = new stream();
let req = request(app.getHttpServer()).post('/file/upload')
.field('FileHash', UUID.v4())
.attach('Chunk', Buffer.alloc(1024, 'fsfs', 'binary'), {filename: 'dd.txt'})
.expect(201)
.end((err, res) => {
done();
});
})
field 相当于application/form中的的普通字段,attach为文件,如果最后一个filename不添加也是可以传上去,只是有的框架会出些问题
service的单元测试
import { Injectable, Inject } from '@nestjs/common';
import { userAppProvidersName, UserApp } from '../../models/user-app.model';
import { Op, where } from 'sequelize';
import { zengtestTry, zengtestTryProvidersName} from '../../models/zeng-testTry.model';
@Injectable()
export class zengtestTryService {
constructor(@Inject(zengtestTryProvidersName) public readonly zengtestTryRepository: typeof zengtestTry) {
}
async getAll(): Promise<zengtestTry[]> {
let res: zengtestTry[] = await this.zengtestTryRepository.findAll();
return res;
}
async addtestTry(data: ItestTry): Promise<zengtestTry> {
let res = await this.zengtestTryRepository.build(data).save();
return res;
}
async updatetestTry(data: {id: number}&Partial<ItestTry>): Promise<number> {
let res = await this.zengtestTryRepository.update(data, {where: {id: data.id}});
return res;
}
async deletetestTry(id: number): Promise<void> {
let res = await this.zengtestTryRepository.destroy({where: {id: id}});
}
}
interface ItestTry {
name: string;
}
测试文件
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { DatabaseModule } from '../../database/database.module';
import { v4 } from 'uuid';
import { where } from 'sequelize/types';
import { zengtestTryProvider } from '../../models/zeng-testTry.model';
import { zengtestTryService } from './zeng-testTry.service';
describe('zeng testTry service', () => {
let service: zengtestTryService;
let module: TestingModule;
beforeAll(async () => {
module = await Test.createTestingModule({
imports: [
DatabaseModule
],
providers: [
zengtestTryProvider,
zengtestTryService
]
}).compile();
service = module.get<zengtestTryService>(zengtestTryService);
});
it('init service', () => {
expect(service != null).toEqual(true);
});
it("add testTry", async () => {
let res = await service.addtestTry({
apiName: 'addTest',
alias: 'addAlias',
isVip: true,
isNormal: true,
isEducation: true,
isTest: true,
isPublic: true
});
await service['zengtestTryRepository'].destroy({where: {id: res.id}});
expect(res.apiName).toEqual('addTest');
});
it('update testTry', async () => {
let res = await service.addtestTry({
apiName: 'addTest2',
alias: 'addAlias',
isVip: true,
isNormal: true,
isEducation: true,
isTest: true,
isPublic: true
});
await service.updatetestTry({id: res.id, alias: 'updataAlias'});
let afterUpdateData = await service['zengtestTryRepository'].findOne({where: {id: res.id}});
expect(afterUpdateData.alias).toEqual('updataAlias');
await service['zengtestTryRepository'].destroy({where: {id: res.id}});
});
it('delete testTrys', async () => {
let res = await service.addtestTry({
apiName: 'deleteTest',
alias: 'addAlias',
isVip: true,
isNormal: true,
isEducation: true,
isTest: true,
isPublic: true
});
let del = await service.deletetestTry(res.id);
let find = await service['zengtestTryRepository'].findOne({where: {id: res.id}});
expect(find).toEqual(null);
});
it('get all', async () => {
let res = await service.addtestTry({
apiName: 'get all test',
alias: 'addAlias',
isVip: true,
isNormal: true,
isEducation: true,
isTest: true,
isPublic: true
});
let res2 = await service.addtestTry({
apiName: 'get all Test2',
alias: 'addAlias',
isVip: true,
isNormal: true,
isEducation: true,
isTest: true,
isPublic: true
});
let list = await service.getAll();
await service['zengtestTryRepository'].destroy({where: {id: res.id}});
await service['zengtestTryRepository'].destroy({where: {id: res2.id}});
expect(list.length).toEqual(2);
let names = [list[0].apiName, list[1].apiName];
expect(names.indexOf('get all test') != -1 && names.indexOf('get all Test2') != -1).toEqual(true);
});
});
好像挺简单的
总结
单元测试的的核心思想就是只管好自己,外部引入都用假的,默认认为都是正常执行,每一个测试都是正常得到期望值,那么整体也就是正常了