1、使用npm安装数据库连接模块
npm install --save pg
2、Nest 与数据库无关,允许与任何 SQL 或 NoSQL 数据库集成,先安装依赖包。
npm install --save @nestjs/typeorm typeorm postgresql
3、测试时需要连接一个放置测试结果的数据库,遇到了一个问题,问题如下:Cannot create a new connection named “default”, because connection with such name already exist and it now has an active connection session.
解决方法:
在TypeOrmModule.forRoot模块添加一个keepConnectionAlive选项,设置其为true
举了例子:
我原来的代码:
// 错误代码
TypeOrmModule.forRoot({
type: 'postgres',
// host:'192.168.10.251',
port: 5432,
username: 'postgres',
password: '123456',
database: 'catsdb_test',
name:'conn_test',
entities: [Cat],
synchronize: true,
}),
更改后的代码:
// 正确代码
TypeOrmModule.forRoot({
type: 'postgres',
// host:'192.168.10.251',
port: 5432,
username: 'postgres',
password: '123456',
database: 'catsdb_test',
name:'conn_test',
entities: [Cat],
synchronize: true,
keepConnectionAlive:true,//**就是加这一句!**
}),
4、测试时遇到另一个问题:
Nest can’t resolve dependencies of the DogRepository (?). Please make sure that the argument Connection at index [0] is available in the TypeOrmModule context.
Potential solutions:
- If Connection is a provider, is it part of the current TypeOrmModule?
- If Connection is exported from a separate @Module, is that module imported within TypeOrmModule?
@Module({
imports: [ /* the Module containing Connection */ ]
})
解决方法:这个只要加入相关的模块就可以编译通过,但是!!!我测试的功能模块是向数据库中插入数据,第一次往数据库插入静态数据成功了,然后我就试图插入动态数据,结果崩了,崩了的后果就是即使我改回静态数据也只是编译通过,数据并没有插进数据库,我感觉我这块的原因是测试语句中请求http服务器失败,但他并没有报错,总之,我解决不了,这里吸取一个教训,那就是一定要进行版本控制!!!血与泪的教训啊!
言归正传,关于上述这个问题官网上有很多讨论,即mock出所有与被测模块相关的模块,具体可以看我下面的代码,如果不适用你的错误,建议看看官网上的讨论,这里附上官网讨论的链接:https://github.com/nestjs/nest/issues/363 .
我研究了很久,发现有两种方法:
(1)mock一个service,你测试的时候会调用模拟的service方法,但因为你这里模拟的是完美的service方法,所以测试编译肯定会通过。但是数据不会跟数据库产生联系。这块的写法可以对比
官网测试文档链接: https://docs.nestjs.cn/6/fundamentals?id=%e6%b5%8b%e8%af%95.和如下关于我写的cats.controller.spec.ts
测试文件的代码如下:
import { Test, TestingModule } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { INestApplication } from '@nestjs/common';
import { Cat } from '@libs/db/models/cat.model';
import { CatsService } from './cats.service ';
import { TypeOrmModule} from '@nestjs/typeorm';
import * as request from 'supertest';
describe('Cats Controller', () => {
let controller:CatsController;
let app: INestApplication;
const catsService = { //此处需要mock一个service,因为目前进行的是controller的单元测试,但是controller需要注入service提供程序,那么就假设service是一个完美的无错误的程序
getAllCattest: () => ({}),
create: () => ({}),
getOneCat: () => ({}),
getAllCat: () => ({}),
postCat: () => ({}),
deleteCat: () => ({}),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [CatsController],
imports:[
TypeOrmModule.forRoot({
type: 'postgres',
port: 5432,
username: 'postgres',
password: '123456',
database: 'catsdb',
name:'conn_test',
entities: [Cat],
synchronize: true,
keepConnectionAlive:true,
}),
TypeOrmModule.forFeature([Cat],'conn_test'),
],
providers: [CatsService],
})
.overrideProvider(CatsService) //在这里负载CatsService
.useValue(catsService) //使用我们刚刚mock的完美service
.compile();
controller = module.get<CatsController>(CatsController);
app = module.createNestApplication();
await app.init();
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
it('getAllCat', (done) => {
request(app.getHttpServer())
.get('/cats/getCatList')
.expect(200)
.end(function (err, res) {
if (err) {
return done.fail(err);
}
expect(res.body).not.toBeNull();
done();
});
});
// for (const item of res0) {
it('/postCat', done => {
request(app.getHttpServer())
.post('/cats/postcat_test')
.send({
id:1,
name:'小猫咪',
})
.expect(201)
.end((error, response) => {
if (error) {
return done.fail(error);
}
expect(response.body).not.toBeNull();
done();
});
});
// }
afterAll(async () => {
await app.close();
});
pool.end();
});
(2)如果不仅要实现通过测试用例,还要实现测试代码与数据库的交互,建议这里不适用mock的service,而是直接在@Module里将提供程序导入。代码如下:
import { Test, TestingModule } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { INestApplication } from '@nestjs/common';
import { CatsModule } from './cats.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Cat } from '@libs/db/model/cat.model';
import { CatsService } from './cats.service';
import * as request from 'supertest';
describe('Cats Controller', () => {
let controller: CatsController;
let app:INestApplication;
// const catsService = {
// getcat:() => ({}),
// create:() =>({}),
// };
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
// controllers: [CatsController],
imports:[
CatsModule,
TypeOrmModule.forRoot({
type: 'postgres',
port: 5432,
username: 'postgres',
password: '123456',
database: 'catsdb',
entities: [Cat],
synchronize: true,
keepConnectionAlive:true,
}),
TypeOrmModule.forFeature([Cat]),
],
providers:[CatsService],
})
// .overrideProvider(CatsService)
// .useValue(catsService)
.compile();
controller = module.get<CatsController>(CatsController);
app = module.createNestApplication();
await app.init();
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
//下面这个测试会将这条数据添加到数据库中
it('/POST /api/cats', done => {
return request(app.getHttpServer())
.post('/cats/postacat')
.send({
id:6,
name: '小花猫',
age: 2,
description: '折耳',
})
.expect(201)
.end((error, response) => {
if (error) {
return done.fail(error);
}
expect(response.body).not.toBeNull();
done();
});
});
afterAll(async () => {
await app.close();
});
});
(3)考虑到以上代码只是实现了静态数据的测试,现实中每个单元测试都会有很多条测试用例,因此这块考虑获取动态数据,为了在测试时获取动态的测试用例,需要引入一个测试用例的数据库,这里使用pgsql,首先需要安装pg依赖包:
npm install @types/pg
在cats.controller.spec.ts文件中连接测试用例数据库,获取数据,然后进行测试,代码如下:
import { Test, TestingModule } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { INestApplication } from '@nestjs/common';
import { CatsModule } from './cats.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Cat } from '@libs/db/model/cat.model';
import { CatsService } from './cats.service';
import * as request from 'supertest';
import { Pool } from 'pg';
describe('Cats Controller', () => {
let controller: CatsController;
let app:INestApplication;
//连接测试用例数据库
const pool = new Pool({
host:'localhost',
port: 5432,
user: 'postgres',
password: '123456',
database: 'catsdb',
max:20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports:[
CatsModule,
TypeOrmModule.forRoot({
type: 'postgres',
port: 5432,
username: 'postgres',
password: '123456',
database: 'TestOutput',
entities: [Cat],
synchronize: true,
keepConnectionAlive:true,
}),
TypeOrmModule.forFeature([Cat]),
],
providers:[CatsService],
})
.compile();
controller = module.get<CatsController>(CatsController);
app = module.createNestApplication();
await app.init();
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
it('/POST /api/cats', done => {
pool.query('select *from cat',(err,result) =>{
if (err) {
return console.error('Error executing query', err.stack)
}
const res0 = result.rows;
for(const item of res0){
request(app.getHttpServer())
.post('/cats/postacat')
.send(item)
.expect(201)
.end((error, response) => {
if (error) {
return done.fail(error);
}
expect(response.body).not.toBeNull();
done();
});
}});
}
)
afterAll(async () => {
await app.close();
});
});
我在这里只使用了pool.query的方法,还有许多其他方法,这里附上官网链接: https://node-postgres.com/api/pool/.
5、对于被测软件来说,一种思路就是穷尽性测试,即考虑其所有的输入组合或者考虑程序所有的执行路径,当这些全部执行无误后,可以认为这款软件是高质量软件,但是这是不现实的。所以测试用例的设计就比较重要, 但是不管是黑盒测试和白盒测试技术,人工设计测试用例工作量都比较大,所以想找一款覆盖面广的自动生成测试用例的工具。还在找。。。