TypeORM 与 Jest 单元测试的连接

Ene*_*neh 5 jestjs typeorm ts-jest

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

\n

更新目录架构

\n
app\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 .env\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 .env.test\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 loadEnv.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 ormconfig-cli.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 connection.ts\n\xe2\x94\x82     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 app.module.ts\n\xe2\x94\x82\xc2\xa0   \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user\n\xe2\x94\x82     \xe2\x94\x82\xc2\xa0\xc2\xa0  \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 entities\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0  \xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80  user.entity.ts\n\xe2\x94\x82\xc2\xa0    \xe2\x94\x82\xc2\xa0\xc2\xa0  \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.module.ts\n\xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.resolver.spec.ts\n\xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.resolver.ts\n\xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.service.spec.ts\n\xe2\x94\x82\xc2\xa0    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 user.service.ts\n
Run Code Online (Sandbox Code Playgroud)\n

更新连接错误

\n

无法创建连接,getConnection().isConnected = false并且\n getConnection(\'test\')(或\'default\')抛出“未找到连接”。错误。

\n
app\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 .env\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 .env.test\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 loadEnv.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 ormconfig-cli.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 connection.ts\n\xe2\x94\x82     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 app.module.ts\n\xe2\x94\x82\xc2\xa0   \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user\n\xe2\x94\x82     \xe2\x94\x82\xc2\xa0\xc2\xa0  \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 entities\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0  \xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80  user.entity.ts\n\xe2\x94\x82\xc2\xa0    \xe2\x94\x82\xc2\xa0\xc2\xa0  \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.module.ts\n\xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.resolver.spec.ts\n\xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.resolver.ts\n\xe2\x94\x82\xc2\xa0\xc2\xa0   \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 user.service.spec.ts\n\xe2\x94\x82\xc2\xa0    \xe2\x94\x82\xc2\xa0\xc2\xa0 \xc2\xa0\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 user.service.ts\n
Run Code Online (Sandbox Code Playgroud)\n

这是设置:

\n
//connection.ts\n\nimport { loadEnv } from \'../loadEnv\';\nimport connectionOptions from \'../ormconfig-cli\';\nloadEnv();\n\n  async create(): Promise<Connection> {\n    const connOptions: ConnectionOptions = connectionOptions.find(option => option.name == process.env.NODE_ENV);\n    return await createConnection({ ...connOptions, name: \'default\' });\n  },\n
Run Code Online (Sandbox Code Playgroud)\n
// .env.test\n\nNODE_ENV=test\n\nTYPEORM_HOST=localhost\nTYPEORM_PORT=5432\nTYPEORM_USERNAME=root\nTYPEORM_PASSWORD=test\nTYPEORM_DATABASE=test\n\n# TEST_DATABASE="postgres://root:test@localhost:5432/test jest"\n
Run Code Online (Sandbox Code Playgroud)\n
// package.json\n\n{\n  ...,\n  "scripts": {\n    ...,\n    "test": "NODE_ENV=test jest",\n    "test:watch": "jest --watch",\n    "test:cov": "jest --coverage",\n    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",\n    "test:e2e": "jest --config ./test/jest-e2e.json",\n  }, {...},\n  "jest": {\n    "moduleFileExtensions": [\n      "js",\n      "json",\n      "ts"\n    ],\n    "rootDir": "src",\n    "testRegex": ".*\\\\.spec\\\\.ts$",\n    "transform": {\n      "^.+\\\\.(t|j)s$": "ts-jest"\n    },\n    "collectCoverageFrom": [\n      "**/*.(t|j)s"\n    ],\n    "coverageDirectory": "../coverage",\n    "testEnvironment": "node",\n    "clearMocks": true\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
// .env.test\n\nNODE_ENV=test\n\nTYPEORM_HOST=localhost\nTYPEORM_PORT=5432\nTYPEORM_USERNAME=root\nTYPEORM_PASSWORD=test\nTYPEORM_DATABASE=test\n\n# TEST_DATABASE="postgres://root:test@localhost:5432/test jest"\n
Run Code Online (Sandbox Code Playgroud)\n
// loadEnv.ts\n\nimport * as dotenv from \'dotenv\';\n\nexport const loadEnv = () => {\n  const loadFile = () => {\n    if (process.env.NODE_ENV === \'test\') return \'.env.test\';\n    return \'.env\';\n  };\n\n  return dotenv.config({\n    path: loadFile(),\n  });\n};\n
Run Code Online (Sandbox Code Playgroud)\n
// ormconfig.ts\n\nimport { loadEnv } from \'./loadEnv\';\nimport { ConnectionOptions } from \'typeorm\';\n\nloadEnv();\n\nconst SnakeNamingStrategy = require(\'typeorm-naming-strategies\')\n  .SnakeNamingStrategy;\n\nconst connectionOptions: ConnectionOptions[] = [\n  {\n    name: \'development\',\n    type: \'postgres\',\n    host: String(process.env.TYPEORM_HOST),\n    port: Number(process.env.TYPEORM_PORT),\n    username: String(process.env.TYPEORM_USERNAME),\n    password: String(process.env.TYPEORM_PASSWORD),\n    database: String(process.env.TYPEORM_DATABASE),\n    synchronize: false,\n    logging: true,\n    cli: {\n      migrationsDir: \'src/migrations\',\n    },\n    namingStrategy: new SnakeNamingStrategy(),\n    entities: [\'dist/**/*.entity{.ts,.js}\'],\n    migrations: [\'dist/src/migrations/*.{js,ts}\'],\n    migrationsTransactionMode: \'each\',\n  },\n  {\n    name: \'test\',\n    type: \'postgres\',\n    host: String(process.env.TYPEORM_HOST),\n    port: Number(process.env.TYPEORM_PORT),\n    username: String(process.env.TYPEORM_USERNAME),\n    password: String(process.env.TYPEORM_PASSWORD),\n    database: String(process.env.TYPEORM_DATABASE),\n    synchronize: false,\n    dropSchema: true,\n    logging: true,\n    cli: {\n      migrationsDir: \'src/migrations\',\n    },\n    namingStrategy: new SnakeNamingStrategy(),\n    entities: [\'dist/**/*.entity{.ts,.js}\'],\n    migrations: [\'dist/src/migrations/*.{js,ts}\'],\n    migrationsTransactionMode: \'each\',\n  },\n];\n\nexport = connectionOptions;\n
Run Code Online (Sandbox Code Playgroud)\n

如果运行npm test src/test/user.service.spec.ts,会得到错误:No connection options were found in any orm configuration files.\n日志console.log("connection.isConnected(): ", connection.isConnected());错误:\nConnectionNotFoundError:未找到连接“默认”。

\n

这是测试用例:

\n
// app.module.ts\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      name: \'development\',\n      type: \'postgres\',\n      host: process.env.TYPEORM_HOST,\n      username: process.env.TYPEORM_USERNAME,\n      password: process.env.TYPEORM_PASSWORD,\n      database: process.env.TYPEORM_DATABASE,\n      migrationsRun: true,\n      synchronize: false,\n      migrationsTransactionMode: \'each\',\n      migrations: [\'dist/src/migrations/*.{js,ts}\'],\n      namingStrategy: new SnakeNamingStrategy(),\n      autoLoadEntities: true,\n    }),\n    TypeOrmModule.forRoot({\n      name: \'test\',\n      type: \'postgres\',\n      host: process.env.TYPEORM_HOST,\n      username: process.env.TYPEORM_USERNAME,\n      password: process.env.TYPEORM_PASSWORD,\n      database: process.env.TYPEORM_DATABASE,\n      logging: false,\n      dropSchema: true,\n      migrationsRun: true,\n      synchronize: false,\n      migrationsTransactionMode: \'each\',\n      migrations: [\'dist/src/migrations/*.{js,ts}\'],\n      namingStrategy: new SnakeNamingStrategy(),\n      autoLoadEntities: true,\n    }),\n    ...,\n  ],\n})\nexport class AppModule {}\n
Run Code Online (Sandbox Code Playgroud)\n

如果不使用connection.create()连接,connection.isConnected()则会如此。

\n
// connection.ts\n\nimport { Connection, createConnection, getConnection, getConnectionOptions } from \'typeorm\';\nimport { loadEnv } from \'../loadEnv\';\n\nloadEnv();\n\nexport const connection = {\n  async create(): Promise<Connection> {\n    const connectionOptions = await getConnectionOptions(process.env.NODE_ENV);\n    return await createConnection({ ...connectionOptions, name: \'default\' });\n  },\n\n  async close() {\n    await getConnection().close();\n  },\n\n  async clear() {\n    const connection = getConnection();\n    const entities = connection.entityMetadatas;\n\n    entities.forEach(async (entity) => {\n      const repo = connection.getRepository(entity.name);\n      await repo.query(`DELETE FROM ${entity.tableName}`);\n    });\n  },\n\n  async isConnected() {\n    return getConnection().isConnected;\n  },\n};\n\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

小智 0

尝试使用ConfigModuleTypeORM. 它将以更干净的方式完成这些工作。此外,即使在使用模块时,您也需要在特定测试文件中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()
Run Code Online (Sandbox Code Playgroud)

详细实现请参考文档https://docs.nestjs.com/techniques/configuration