使用Jest单元测试的TypeORM连接



我有两个数据库,一个用于开发,另一个用于测试。我想在运行jest测试时连接到测试数据库,我设置了2个.env配置,开发使用.env,测试使用.env.test。但是单元测试不能通过connection.ts连接数据库。

更新目录架构

app
├── .env
├── .env.test
├── loadEnv.ts
├── package.json
├── ormconfig-cli.ts
├── src
│     ├── connection.ts
│     ├── app.module.ts
│     ├── user
│     │    ├── entities
│     │    │     └──  user.entity.ts
│     │    ├── user.module.ts
│     │    ├── user.resolver.spec.ts
│     │    ├── user.resolver.ts
│     │    ├── user.service.spec.ts
│     │    └── user.service.ts

更新连接错误

无法创建连接,getConnection().isConnected = false和CCD_ 6(或CCD_;未找到连接"错误

//connection.ts
import { loadEnv } from '../loadEnv';
import connectionOptions from '../ormconfig-cli';
loadEnv();
async create(): Promise<Connection> {
const connOptions: ConnectionOptions = connectionOptions.find(option => option.name == process.env.NODE_ENV);
return await createConnection({ ...connOptions, name: 'default' });
},

设置如下:

// package.json
{
...,
"scripts": {
...,
"test": "NODE_ENV=test jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
}, {...},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\.spec\.ts$",
"transform": {
"^.+\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node",
"clearMocks": true
}
}
// .env.test
NODE_ENV=test
TYPEORM_HOST=localhost
TYPEORM_PORT=5432
TYPEORM_USERNAME=root
TYPEORM_PASSWORD=test
TYPEORM_DATABASE=test
# TEST_DATABASE="postgres://root:test@localhost:5432/test jest"
// loadEnv.ts
import * as dotenv from 'dotenv';
export const loadEnv = () => {
const loadFile = () => {
if (process.env.NODE_ENV === 'test') return '.env.test';
return '.env';
};
return dotenv.config({
path: loadFile(),
});
};
// ormconfig.ts
import { loadEnv } from './loadEnv';
import { ConnectionOptions } from 'typeorm';
loadEnv();
const SnakeNamingStrategy = require('typeorm-naming-strategies')
.SnakeNamingStrategy;
const connectionOptions: ConnectionOptions[] = [
{
name: 'development',
type: 'postgres',
host: String(process.env.TYPEORM_HOST),
port: Number(process.env.TYPEORM_PORT),
username: String(process.env.TYPEORM_USERNAME),
password: String(process.env.TYPEORM_PASSWORD),
database: String(process.env.TYPEORM_DATABASE),
synchronize: false,
logging: true,
cli: {
migrationsDir: 'src/migrations',
},
namingStrategy: new SnakeNamingStrategy(),
entities: ['dist/**/*.entity{.ts,.js}'],
migrations: ['dist/src/migrations/*.{js,ts}'],
migrationsTransactionMode: 'each',
},
{
name: 'test',
type: 'postgres',
host: String(process.env.TYPEORM_HOST),
port: Number(process.env.TYPEORM_PORT),
username: String(process.env.TYPEORM_USERNAME),
password: String(process.env.TYPEORM_PASSWORD),
database: String(process.env.TYPEORM_DATABASE),
synchronize: false,
dropSchema: true,
logging: true,
cli: {
migrationsDir: 'src/migrations',
},
namingStrategy: new SnakeNamingStrategy(),
entities: ['dist/**/*.entity{.ts,.js}'],
migrations: ['dist/src/migrations/*.{js,ts}'],
migrationsTransactionMode: 'each',
},
];
export = connectionOptions;
// app.module.ts
@Module({
imports: [
TypeOrmModule.forRoot({
name: 'development',
type: 'postgres',
host: process.env.TYPEORM_HOST,
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE,
migrationsRun: true,
synchronize: false,
migrationsTransactionMode: 'each',
migrations: ['dist/src/migrations/*.{js,ts}'],
namingStrategy: new SnakeNamingStrategy(),
autoLoadEntities: true,
}),
TypeOrmModule.forRoot({
name: 'test',
type: 'postgres',
host: process.env.TYPEORM_HOST,
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE,
logging: false,
dropSchema: true,
migrationsRun: true,
synchronize: false,
migrationsTransactionMode: 'each',
migrations: ['dist/src/migrations/*.{js,ts}'],
namingStrategy: new SnakeNamingStrategy(),
autoLoadEntities: true,
}),
...,
],
})
export class AppModule {}
// connection.ts
import { Connection, createConnection, getConnection, getConnectionOptions } from 'typeorm';
import { loadEnv } from '../loadEnv';
loadEnv();
export const connection = {
async create(): Promise<Connection> {
const connectionOptions = await getConnectionOptions(process.env.NODE_ENV);
return await createConnection({ ...connectionOptions, name: 'default' });
},
async close() {
await getConnection().close();
},
async clear() {
const connection = getConnection();
const entities = connection.entityMetadatas;
entities.forEach(async (entity) => {
const repo = connection.getRepository(entity.name);
await repo.query(`DELETE FROM ${entity.tableName}`);
});
},
async isConnected() {
return getConnection().isConnected;
},
};

如果运行npm test src/test/user.service.spec.ts,将得到错误:在任何orm配置文件中都找不到连接选项。日志console.log("connection.isConnected(): ", connection.isConnected());获取错误:ConnectionNotFoundError:Connection;默认";未找到。

以下是测试用例:

import { getConnection, Repository } from 'typeorm';
import { createMock } from '@golevelup/nestjs-testing';
import { User } from '../user/user.entity';
import { connection } from '../connection';
describe('UserService', () => {
beforeAll(async () => {
await connection.create();
});
afterAll(async () => {
await connection.clear();
await connection.close();
});
describe('beforeAll connection.create()', async () => {
const repo = createMock<Repository<User>>();
it('should create user', function() {
console.log('env: ', process.env.NODE_ENV); // env: test
console.log("connection.isConnected(): ", connection.isConnected());
const user = {
id: 'uuid',
avatar: 'avatar',
name: 'user A',
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: new Date(),
};
console.log(user);
repo.create(user);
repo.find.mockResolvedValue([user]);
});
});
});

如果不使用connection.create()进行连接,则connection.isConnected()将为true。

...
beforeAll(async () => {
await createConnection({
type: "postgres",
host: "localhost",
port: 5432,
username: "root",
password: "test",
database: "test",
logging: false,
});
});
...

如何通过测试配置更新设置并连接数据库?

尝试使用TypeORMConfigModule。它会以一种更干净的方式来做这些事情。此外,即使在使用config模块时,也需要在特定的测试文件中指定测试config(.env)文件的路径。

beforeEach块内的.spec.ts文件中使用以下代码

const module: TestingModule = Test.createTestingModule({[
imports: [
ConfigModule.forRoot({
encFilePath: '<your env file path with reference to the project root>'
})
],
providers: []
...
]}).compile()

有关详细实施,请参阅文档https://docs.nestjs.com/techniques/configuration

最新更新