NestJS 测试:装饰器不是函数
Posted
技术标签:
【中文标题】NestJS 测试:装饰器不是函数【英文标题】:NestJS Testing: decorator is not a function 【发布时间】:2021-01-20 16:40:26 【问题描述】:我的依赖:
"@nestjs/common": "7.4.4",
"@nestjs/core": "7.4.4",
"typescript": "4.0.2",
"jest": "26.4.2",
"jest-junit": "11.1.0",
"ts-jest": "26.3.0",
我有一个自定义装饰器:
import Inject from "@nestjs/common";
import DATABASE_SERVICE from "./database.constants";
export const InjectDatabase = () => Inject(DATABASE_SERVICE);
我在构造函数中将它用于我愿意通过测试覆盖的服务:
import
DatabaseService,
InjectDatabase
from "@infra/modules";
import Injectable from "@nestjs/common";
@Injectable()
export class MyService
constructor(
@InjectDatabase() private readonly db: DatabaseService
)
这是我设置测试模块的方式:
import Test from "@nestjs/testing";
import MyService from "../../../src/shared/services/my.service";
import SharedModule from "../../../src/shared/shared.module";
describe(`MyService`, () =>
let myService: MyService;
beforeEach(async () =>
const moduleRef = await Test.createTestingModule(
imports: [SharedModule]
).compile();
myService = moduleRef.get<MyService>(MyService);
);
test("tests", () =>
// console.log("test");
);
);
SharedModule 是一个带有@Global()
装饰器的模块,并在providers/exports 中包含MyService
。
当我尝试执行测试时,出现错误:
TypeError: modules_1.InjectDatabase is not a function
51 |
52 | constructor(
> 53 | @InjectDatabase() private readonly adb_db: DatabaseService,
| ^
56 | )
at Object.<anonymous> (apps/workers/my/src/shared/services/my.service.ts:53:6)
at Object.<anonymous> (apps/workers/my/test/shared/services/my.service.unit.test.ts:8:1)
我按照上面的跟踪和步骤进行操作:
在测试中使用服务导入文件:import MyService from "../../../src/shared/services/my.service";
在服务构造函数中的 @InjectDatabase()
处引发错误
如果我从@InjectDatabase
切换到@Inject(DATABASE_SERVICE)
:
@Injectable()
export class MyService
constructor(
@Inject(DATABASE_SERVICE) private readonly db: DatabaseService
)
我收到另一个错误:
Error: Nest can't resolve dependencies of the CacheService (?). Please make sure that the argument dependency at index [0] is available in the RootTestModule context.
我尝试这样设置测试模块:
const moduleRef = await Test.createTestingModule(
imports: [DatabaseModule],
providers: [
provide: DATABASE_SERVICE,
useClass: DatabaseService
,
MyService
]
).compile();
但它没有帮助,同样的问题:
Error: Nest can't resolve dependencies of the CacheService (?).
我的tsconfig.json
编译器选项:
"compilerOptions":
"target": "es2018",
"module": "commonjs",
"outDir": "dist/",
"esModuleInterop": true,
"strict": true,
"sourceRoot": "/",
"sourceMap": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictPropertyInitialization": false,
"removeComments": true,
"resolveJsonModule": true
我在jest.config.js
:
setupFiles: ["./jest-setup-file.ts"],
此文件仅导入反射库:
import 'reflect-metadata';
我尝试在MyService
声明之前添加到my.service.ts
:
console.log('InjectDatabase', InjectDatabase)
并收到:
InjectDatabase: undefined
因此,Jest 似乎无法解析导入,或者 typescript 配置有问题。
在MyService
中导入的装饰器函数为:
import
DatabaseService,
InjectDatabase
from "@infra/modules";
我的jest.config.js
:
module.exports =
bail: 0,
verbose: true,
preset: "ts-jest",
testEnvironment: "node",
roots: ["<rootDir>/libs", "<rootDir>/apps"],
testRegex: ".*\\.test\\.ts$",
testPathIgnorePatterns: ["/node_modules/", "/dist/", "/build/"],
moduleFileExtensions: ["ts", "js", "json"],
moduleNameMapper:
"@common": "<rootDir>/libs/common/src",
"@common/(.*)": "<rootDir>/libs/common/src/$1",
"@infra": "<rootDir>/libs/infrastructure/src",
"@infra/(.*)": "<rootDir>/libs/infrastructure/src/$1"
,
transform:
"^.+\\.ts?$": "ts-jest"
,
setupFiles: ["./jest-setup-file.ts"],
collectCoverage: true,
coverageThreshold:
global:
branches: 80,
functions: 80,
lines: 80,
statements: 80
,
coverageReporters: ["json", "lcov", "text", "clover"],
coveragePathIgnorePatterns: ["/node_modules/"]
;
可能moduleNameMapper
无法正确解析"@infra/(.*)": "<rootDir>/libs/infrastructure/src/$1"
为"@infra/modules"
?
在测试之外 - 一切都按预期工作。
如何正确设置 jest/typescript/nest 以便正确识别我的自定义装饰器?
【问题讨论】:
我不明白您编写自定义装饰器的方式。您是否尝试过 createParamDecorator 方法,如文档中所述? docs.nestjs.com/custom-decorators @Seraf 好吧,我尝试这样做,但似乎开玩笑无法使用该函数解析模块的路径,并以未定义结束。 你能提供最低限度的复制吗?在使用自定义装饰器并对其进行测试之前,我没有遇到任何问题。 【参考方案1】:经过更好的调试后,我发现 Jest 无法将带有子文件夹的路径别名解析为模块,而不是加载导入的内容,而是返回未定义的内容。 jest.config.js 中的设置:
"@infra": "<rootDir>/libs/infrastructure/src",
"@infra/(.*)": "<rootDir>/libs/infrastructure/src/$1"
所以上面的第二行不适用于 Jest。
所有具有以下路径的导入:
import Stuff from "@infra/sub/folder/module"
正在返回undefined
当路径像:
import Stuff from "@infra
像魅力一样工作。
我修复了 @infra
lib 中的桶文件以正确导出内容并修复导入以使用缩短路径,这有助于解决问题。
我仍然很好奇为什么要设置 Jest:
"@infra/(.*)": "<rootDir>/libs/infrastructure/src/$1"
在下面:
moduleNameMapper
不工作。
【讨论】:
以上是关于NestJS 测试:装饰器不是函数的主要内容,如果未能解决你的问题,请参考以下文章