繁体   English   中英

无法在 NestJs 服务上创建 Jest 测试模块。 获取 Nest 无法解析 UsersService (?, ConfigService) 的依赖关系

[英]Unable to create Jest testing module on NestJs service. Geting Nest can't resolve dependencies of the UsersService (?, ConfigService)

这是我第一次在 stackoverflow 上提出问题:)。

所以我正在开发一个测试/学习应用程序来学习如何使用 NestJS 和 Vue。 我目前正在尝试实现几个服务器端单元测试(使用 Jest)。 尝试从我的 UsersService 创建测试模块时,我在运行“npm test users.service.spec”时收到以下错误

Nest 无法解析 UsersService (?, ConfigService) 的依赖关系。 请确保索引 [0] 处的参数在 _RootTestModule 上下文中可用。

在 Injector.lookupComponentInExports (../node_modules/@nestjs/core/injector/injector.js:183:19)

我不确定是我错误地实例化了测试model,还是误解了config.service的注入,代码本身可以工作,但可能实现不正确。 有谁知道如何解决这个问题?

Git 链接: https://github.com/Lindul/FuelTracker_NestJs_MySql_Vue.git

users.service.spec.ts

import { Test } from '@nestjs/testing';
import { UsersService } from './users.service';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { ConfigService } from '../shared/config/config.service';
describe('User Service Tests', () => {

    let loginTeste: UserLoginRegRequestDto = {
        login: 'LoginJestTeste',
        password: 'PassJestTeste',
    }

    const userMock: UserDto = {
        id: 1,
        login: 'hugombsantos',
        password: 'wefewkfnwekfnwekjnf',
        isActive: true,
        needChangePass: false,
        userType: 0,

    };

    const dataFindAllMock: UserDto[] = [{
        id: 1,
        login: 'hugombsantos',
        password: 'wefewkfnwekfnwekjnf',
        isActive: true,
        needChangePass: false,
        userType: 0,

    }, {
        id: 2,
        login: 'user2',
        password: 'sdgsdgdsgsdgsgsdg',
        isActive: true,
        needChangePass: false,
        userType: 0,
    }];

    let service: UsersService;
    beforeEach(async () => {

        const module = await Test.createTestingModule({
            providers: [
                ConfigService,
                UsersService,
            ],
        }).compile();

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


    it('UsersService está defenido', () => {
        expect(service).toBeDefined();
    });   

});

用户服务.ts

import { Injectable, Inject, HttpException, HttpStatus } from '@nestjs/common';
import { Users } from '../models/users.schema';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { UserLoginResponseDto } from './dto/user-login-response.dto';
import { sign } from 'jsonwebtoken';
import { ConfigService } from '../shared/config/config.service';
import { JwtPayload } from './auth/jwt-payload.model';
import { ErroMessageDto } from '../shared/config/dto/erro-message.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import bcrypt = require('bcrypt-nodejs');
const SALT_FACTOR = 8;

@Injectable()
export class UsersService {

    constructor(
        @Inject('UsersRepository') private usersRepository: typeof Users,
        private readonly configService: ConfigService,
    ) { }

    /* istanbul ignore next */
    async findAll(): Promise<UserDto[]> {
        const users = await this.usersRepository.findAll<Users>();
        return users.map(user => {
            return new UserDto(user);
        });
    }
    /* istanbul ignore next */
    async findUser(id: number): Promise<Users> {
        const user = await this.usersRepository.findOne<Users>({
            where: { id },
        });
        return user;
    }
    /* istanbul ignore next */
    async findUserformLogin(login: string): Promise<UserDto> {
        return await this.usersRepository.findOne<Users>({
            where: { login },
        });
    }
    /* istanbul ignore next */
    async findUserforLogin(id: number, login: string): Promise<Users> {
        return await this.usersRepository.findOne<Users>({
            where: { id, login },
        });
    }
    /* istanbul ignore next */
    async creatUserOnDb(createUser: UserLoginRegRequestDto): Promise<Users> {
        try {
            const user = new Users();
            user.login = createUser.login;
            user.password = await this.hashPass(createUser.password);
            return await user.save();
        } catch (err) {
            if (err.original.code === 'ER_DUP_ENTRY') {
                throw new HttpException(
                    new ErroMessageDto(
                        HttpStatus.CONFLICT,
                        `Login '${err.errors[0].value}' already exists`),
                    HttpStatus.CONFLICT,
                );
            }
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.INTERNAL_SERVER_ERROR,
                    err),
                HttpStatus.INTERNAL_SERVER_ERROR,
            );
        }
    }
    /* istanbul ignore next */
    async updateUserOnDb(user: Users): Promise<Users> {
        try {
            return await user.save();
        } catch (err) {
            if (err.original.code === 'ER_DUP_ENTRY') {
                throw new HttpException(
                    new ErroMessageDto(
                        HttpStatus.CONFLICT,
                        `Login '${err.errors[0].value}' already exists`),
                    HttpStatus.CONFLICT,
                );
            }
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.INTERNAL_SERVER_ERROR,
                    err),
                HttpStatus.INTERNAL_SERVER_ERROR,
            );
        }
    }

    /* istanbul ignore next */
    async delete(id: number): Promise<UserDto> {
        const user = await this.findUser(+id);
        await user.destroy();
        return new UserDto(user);
    }

    async login(
        userLoginRequestDto: UserLoginRegRequestDto,
    ): Promise<UserLoginResponseDto> {

        const login = userLoginRequestDto.login;
        const password = userLoginRequestDto.password;
        const user = await this.findUserformLogin(login);

        if (!user) {
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.UNAUTHORIZED,
                    'Invalid login or password.'),
                HttpStatus.UNAUTHORIZED,
            );
        }

        const isMatch = await this.comparePass(password, user.password);

        if (!isMatch) {
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.UNAUTHORIZED,
                    'Invalid login or password.'),
                HttpStatus.UNAUTHORIZED,
            );
        }

        const token = await this.signToken(user);

        return new UserLoginResponseDto(token);
    }

    async create(createUser: UserLoginRegRequestDto): Promise<UserLoginResponseDto> {

        const userData = await this.creatUserOnDb(createUser);

        // when registering then log user in automatically by returning a token
        const token = await this.signToken(userData);

        return new UserLoginResponseDto(token);

    }

    async updateUser(id: number | string, updateUserDto: UpdateUserDto): Promise<UserLoginResponseDto> {

        const user = await this.findUser(+id);

        if (!user) {
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.NOT_FOUND,
                    'User not found.'),
                HttpStatus.NOT_FOUND,
            );
        }

        user.login = updateUserDto.login || user.login;
        user.userType = updateUserDto.userType || user.userType;
        user.needChangePass = false;

        const isMatch = await this.comparePass(updateUserDto.password, user.password);
        if (updateUserDto.password && !isMatch) {
            user.password = await this.hashPass(updateUserDto.password);
        } else {
            user.password = user.password;
        }

        const userData = await this.updateUserOnDb(user);
        const token = await this.signToken(userData);

        return new UserLoginResponseDto(token);

    }

    async signToken(user: UserDto): Promise<string> {

        const payload: JwtPayload = {
            id: user.id,
            login: user.login,
        };
        const token = sign(payload, this.configService.jwtConfig.jwtPrivateKey,
            {
                expiresIn: this.configService.jwtConfig.valideTime,
            });
        return token;
    }

    async hashPass(passToHash: string): Promise<string> {
        const saltValue = await bcrypt.genSaltSync(SALT_FACTOR);
        return await bcrypt.hashSync(passToHash, saltValue);
    }

    async comparePass(passToCheck: string, correntPass: string) {
        return await bcrypt.compareSync(passToCheck, correntPass);
    }
}

users.modules.ts

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import {userProviders} from './users.providers';
import { DatabaseModule } from '../database/database.module';
import { JwtStrategy } from './auth/jwt-strategy';
import { ConfigService } from '../shared/config/config.service';

@Module({
  imports: [DatabaseModule, ConfigService],
  controllers: [UsersController],
  providers: [UsersService,
    ...userProviders, JwtStrategy],
  exports: [UsersService],

})

export class UsersModule {}

配置服务.ts

import { Injectable } from '@nestjs/common';
import { JwtConfig } from './interfaces/jwt-config.interface';
import { config } from '../../../config/config.JwT';
import { config as dbConfigData } from '../../../config/config.db';
import { SequelizeOrmConfig } from './interfaces/sequelize-orm-config.interface';

@Injectable()
export class ConfigService {
    get sequelizeOrmConfig(): SequelizeOrmConfig {
        return dbConfigData.databaseOpt;
    }

    get jwtConfig(): JwtConfig {
        return {
            jwtPrivateKey: config.jwtPrivateKey,
            valideTime: config.valideTime,
        };
    }
}

您需要为 Nest 提供一些值,以便为您的UserRepository注入。 看起来您正在使用 TypeORM @InjectRepository()装饰器,因此在您的测试模块中,您需要在您的提供程序下添加类似这样的内容

{
  provide: getRepositoryToken('UsersRepository'),
  useValue: MyMockUserRepo,
}

这样 Nest 就可以知道为该字符串注入什么值。 MyMockUserRepo将是您的模拟存储库功能,因此您不会对后端进行实际的数据库调用

暂无
暂无

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

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