Nest не может разрешить зависимости UsersService - PullRequest
0 голосов
/ 22 марта 2020

Я пытаюсь настроить авторизацию в Nest Js, используя Mon goose через службу пользователя. При попытке выполнить модульное тестирование я получаю следующие ошибки:

enter image description here

Я понимаю, что UserModel внедряется в службу UsersService и должна быть устранена, когда используя UsersModule, но я не могу понять, как это сделать при создании TestingModule. Пожалуйста, кто-нибудь может пролить свет на это для меня?

Код ниже, спасибо:

МОДУЛЬ ПОЛЬЗОВАТЕЛЯ

## 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.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();
  });
});

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Объединив предложение Мачей выше и этот блог: 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 также нужно было создать фиктивный класс под mocks , как предложено в вышеприведенной статье:

## /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"
        }
    }   
}

, который насмехается над классом ниже (такой же, как выше, но уменьшен ради этого объяснения) ):

## /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();
  }     
}
1 голос
/ 22 марта 2020

В модульных тестах вы должны смоделировать все необходимые зависимости для AuthService. Это не тест e2e, вам не следует инициализировать MongooseModule здесь. Ваш beforeEach должен выглядеть так:

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

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