我一整天都收到这个错误:
Nest can't resolve dependencies of the ClubsService (ClubsApiService, AuthApiService, ClubFollowersRepo, ClubsRepo, ClubPrivacyRepo, ?). Please make sure that the argument DatabaseConnection at index [5] is available in the ClubsModule context.
Potential solutions:
- If DatabaseConnection is a provider, is it part of the current ClubsModule?
- If DatabaseConnection is exported from a separate @Module, is that module imported within ClubsModule?
@Module({
imports: [ /* the Module containing DatabaseConnection */ ]
})
我认为问题在于我没有模拟 Mongo DB 连接。错误很明显,ClubsService
中的@InjectConnection
应该被模拟(见下文)。
俱乐部服务:
@Injectable()
export class ClubsService {
constructor(
private readonly clubsApiService: ClubsApiService,
private readonly authApiService: AuthApiService,
private readonly clubFollowersRepo: ClubFollowersRepo,
private readonly clubsRepo: ClubsRepo,
private readonly clubPrivacyRepo: ClubPrivacyRepo,
@InjectConnection() private readonly connection: Connection, // <--- THIS GUY
) {}
// ...
}
问题是我正在执行的测试文件与 ClubsService
所在的模块不同。所以在不同的模块中(我们称之为 YModule
),我有这段代码:
Y模块:
import { getConnectionToken } from '@nestjs/mongoose';
import { MongoMemoryServer } from 'mongodb-memory-server';
import { Connection, connect } from 'mongoose';
describe('YService.spec.ts in YModule', () => {
beforeAll(async () => {
mongod = await MongoMemoryServer.create();
const uri = mongod.getUri();
mongoConnection = (await connect(uri)).connection;
});
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
// ...
],
imports: [ClubsModule], // <--- ClubsModule is not provider, but imported module
})
.overrideProvider(getConnectionToken())
.useValue(mongoConnection)
.compile();
});
});
这种使用 getConnectionToken()
的方法将不起作用,因为我必须模拟来自导入的 ClubsModule
而不是提供者的连接。
您将如何模拟注入(inject)到您导入的不同模块中的连接?
非常感谢! :)
最佳答案
正如 Jay McDoniel 在帖子评论中提到的,您不应该在单元测试文件中导入模块,而是模拟所需的依赖项。这是为什么?考虑上述问题中的示例:
ClubsModule
具有可以用内存数据库服务器替换的连接依赖性,这是真的,但这应该在 ClubsModule
内完成本身(clubs
文件夹),不在不同模块之外。
你真正想在外面做什么ClubsModule
,比方说,在 YModule
(y
文件夹),用于模拟每个提供者 ClubsModule
您在 YModule
的测试文件中使用的导出.
这是有道理的,因为您应该测试 ClubsModule
仅在其模块内的特定依赖项,其他任何地方都只是模拟它。
我原装进口ClubsModule
因为我想使用 ClubsModule
的存储库(提供者)导出。但后来我意识到我不想测试存储库函数的功能,我已经在 ClubsModule
中测试了它们,因此无需执行两次。相反,模拟存储库是个好主意。
代码示例:
y.service.spec.ts
:
import { YService } from './y.service'; // <--- For illustration; Provider within YModule
import { ClubsRepo } from '../clubs/clubs.repo'; // <--- Import the real Repository Provider from different Module (ClubsModule)
describe('y.service.spec.ts in YModule', () => {
const clubsRepo = { // <--- Mocking ClubRepo's functions used within this test file
insertMany: () => Promise.resolve([]),
deleteMany: () => Promise.resolve(),
}
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ClubsRepo, // <--- The real Repository Provider from the import statement above
],
})
.overrideProvider(ClubsRepo) // <--- Overriding the Repository Provider from imports
.useValue(clubsRepo) // <--- Overriding to the mock 'clubsRepo' (const above)
.compile();
service = module.get<YService>(YService); // <--- For illustration; unlike ClubsRepo, this provider resides within this module
});
it('example', () => {
// ...
jest.spyOn(clubsRepo, 'insertMany'); // <--- Using "insertMany" from the mocked clubsRepo (the const) defined at the beginning
// ...
});
});
导入原因ClubsRepo
到测试文件 y.service.spec.ts
是因为y.service.ts
(YModule
中的实际 Provider)使用 ClubsRepo
的功能.在这种情况下,不要忘记导入 ClubsModule
在y.module.ts
也是。
y.module.ts
:
import { ClubsModule } from '../clubs/clubs.module';
@Module({
imports: [
// ...
ClubsModule, // <--- Don't forget this line
// ...
],
providers: [
// ...
],
})
export class YModule {}
就是这样,测试愉快! :)
关于node.js - NestJS 模拟从不同模块导入的注入(inject)连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73709756/