简体   繁体   English

Nest 无法解析 UsersService 的依赖关系

[英]Nest can't resolve dependencies of the UsersService

I am trying to set up Authorisation in NestJs using Mongoose via a User Service.我正在尝试通过用户服务使用 Mongoose 在 NestJs 中设置授权。 I'm getting the following errors when trying to Unit Test:尝试单元测试时出现以下错误:

在此处输入图片说明

I understand that the UserModel is injected into the UsersService and needs to be resolved when using the UsersModule but I can't work out how to do this when creating the TestingModule.我知道 UserModel 被注入到 UsersService 中,需要在使用 UsersModule 时解决,但在创建 TestingModule 时我不知道如何做到这一点。 Please can someone shed some light on this for me?请有人能帮我解释一下吗?

Code is below, thanks:代码如下,谢谢:

USER MODULE用户模块

## users.module.ts

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';

@Module({
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}
## users.service.ts

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from './interfaces/user.interface';
import { CreateUserDto } from './dto/create-user.dto';

@Injectable()
export class UsersService {
  constructor(@InjectModel('User') private readonly userModel: Model<User>) {}  

  async store(userData: CreateUserDto): Promise<User> {
    const newUser = new this.userModel(userData);
    return newUser.save();
  }

  async find(data: Record<string, any> = {}) {
    return this.userModel
        .findOne(data)
        .exec();
  }

  async findById(id: string): Promise<User> {
    return this.userModel
        .findById(id)
        .exec();
  } 

  async findByIdOrFail(id: string): Promise<User> {
    return this.userModel
        .findById(id)
        .orFail()
        .exec();
  }

  async update(id: string, data: Record<string, any> = {}): Promise<User> {
    return this.userModel
        .findByIdAndUpdate(id, data, {
            runValidators: true,
            useFindAndModify: false,
            new: true,
        })
        .orFail()
        .exec();
  }

  async destroy(id: string): Promise<User> {
    return this.userModel
        .findByIdAndRemove(id, {
           useFindAndModify: false,
        })
        .orFail()
        .exec();        
  }     
}

AUTH MODULE认证模块

## auth.module.ts

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';

@Module({
  imports: [UsersModule],
  providers: [AuthService]
})
export class AuthModule {}

## auth.service.ts

import { Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';

@Injectable()
export class AuthService {
    constructor(private usersService: UsersService) {}  
}

AUTH SERVICE TEST授权服务测试

## auth.service.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { MongooseModule } from '@nestjs/mongoose';
import { MongoMemoryServer } from 'mongodb-memory-server';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { UserSchema } from '../users/schemas/user.schema';

const mongod = new MongoMemoryServer();

describe('AuthService', () => {
  let service: AuthService;

  beforeEach(async () => {
    const uri = await mongod.getUri();

    const module: TestingModule = await Test.createTestingModule({
      imports: [
        MongooseModule.forRoot(uri, {
          useNewUrlParser: true,
          useUnifiedTopology: true,
        }),
        MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]), 
        UsersModule,        
      ],
      providers: [
        AuthService
      ],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});

In unit tests, you should mock all necessary dependencies for AuthService.在单元测试中,您应该模拟 AuthService 的所有必要依赖项。 It's not e2e test, you shouldn't initialize MongooseModule here.这不是 e2e 测试,你不应该在这里初始化 MongooseModule。 Your beforeEach should look like that:你 beforeEach 应该是这样的:

 beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        AuthService,
        { provide: UsersService, useValue: createSpyObj(UsersService) }
      ]
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

Combining Maciej's suggestion above and this blog: https://medium.com/@davguij/mocking-typescript-classes-with-jest-8ef992170d1 , I arrived at the following solution:结合上面 Maciej 的建议和这个博客: https : //medium.com/@davguij/mocking-typescript-classes-with-jest-8ef992170d1 ,我得到了以下解决方案:

## /auth/auth.service.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';

jest.mock('../users/users.service');

describe.only('AuthService', () => {
  let service: AuthService;

  beforeEach(async () => {

    const module: TestingModule = await Test.createTestingModule({
      imports: [
        UsersModule,
      ],
      providers: [
        AuthService,
      ],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  it('should validate user ok', async () => {
    const res = await service.validateUser('username');
    expect(res).toBeDefined();
  });
});

I also had to create a mock class, under mocks as suggested in the above article:我也不得不创建一个模拟类,在嘲笑的上述文章中建议:

## /users/__mocks__/users.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {

    async find(data: Record<string, any> = {}) {
        return {
            "firstname": "firstname",
            "lastname": "lastname"
        }
    }   
}

which mocks the below class (same as above, but reduced for the sake of this explanation):它模拟了下面的类(与上面相同,但为了这个解释而减少了):

## /users/users.service.ts

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from './interfaces/user.interface';

@Injectable()
export class UsersService {
  constructor(@InjectModel('User') private readonly userModel: Model<User>) {}  

  async find(data: Record<string, any> = {}) {
    return this.userModel
        .findOne(data)
        .exec();
  }     
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM