TypeORM连接与Jest单元测试

iqjalb3h  于 2023-08-01  发布在  Jest
关注(0)|答案(1)|浏览(198)

我有2个db,一个用于开发,一个用于测试。我想在运行jest test时连接到测试数据库,我设置了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 = falsegetConnection('test')(或'default')抛出“未找到连接”错误。

//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:未找到连接“default”。
下面是测试用例:

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,
    });
  });

...


我怎样才能更新我的设置和连接数据库通过我的测试配置?

j91ykkif

j91ykkif1#

尝试使用TypeORM的ConfigModule。它会以一种更干净的方式做这些事情。此外,即使使用配置模块,您也需要在特定的测试文件中指定测试配置(.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

相关问题