如何使用 NestJs 在开玩笑的测试用例中使用 UserDocument/UserModel

How do I use UserDocument/UserModel in jest Testcases using NestJs

我正在尝试使用带有有趣测试​​用例的 nestjs 向数据库添加实际值。

测试用例的主要目的是实际检查写入的数据库值和从数据库中检索的值。所以我没有模拟任何 savefind 方法,因为我想与数据库建立实际连接并从那里检索记录。因此,如果不模拟 save()find() 方法,我将无法获得测试用例 运行。没有它编译失败。

我被 users.service.spec.ts 文件困住了,我想在其中使用 UserDocument 及其方法 create(),findAll().

//user.entity.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
    
  @Prop({ unique: true })
  username: string;

  @Prop()
  age: number;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);
// User.module.ts

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { MongooseModule } from '@nestjs/mongoose'
import { User, UserSchema } from './schemas/user.schema'
import { UsersController } from './users.controller';

@Module({
  imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService]
})
export class UsersModule {}
// users.controller.ts

import { Controller, Get, Post, Body, Patch, Param, Delete,UseGuards } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';


@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

}
//users.service.ts

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User, UserDocument } from './schemas/user.schema';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';

@Injectable()
export class UsersService {
   constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}

  async create(createUserDto: CreateUserDto): Promise<User> {
   const createdUser = new this.userModel(createUserDto);
    return await createdUser.save();
  }

  async findAll(): Promise<User[]> {
    return await this.userModel.find().exec();
  }

}
//users.service.spec.ts

import { Test, TestingModule } from '@nestjs/testing'
import { UsersService } from './users.service'
import { AppConfigModule } from '../config/app-config.module'
import { AppConfigService } from '../config/app-config.service'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { MongooseModule, getModelToken } from '@nestjs/mongoose'
import { PaginationQuery } from 'src/helpers/pagination/pagination-query.dto'
import { User, UserSchema, UserDocument } from './entities/user.entity'

describe('UsersService', () => {
  let service: UsersService
  let userDocument: UserDocument

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          cache: true
        }),
        MongooseModule.forRootAsync({
          imports: [AppConfigModule],
          inject: [AppConfigService],
          useFactory: (config: AppConfigService) => ({
            uri: `mongodb://${config.TESTDATABASE_HOST}:${config.TESTDATABSE_PORT}`,
            dbName: config.TESTDATABASE_NAME
          })
        })
      ],
      providers: [
        UsersService,
        {
          provide: getModelToken(User.name),
          useValue: UserDocument         // <----------- Not able to understand what will go here
        }
      ]
    }).compile()

    service = module.get<UsersService>(UsersService)
    userDocument = module.get<UserDocument>(UserDocument) // <---- As this is type here not accepting value
  })

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

  it('create test data', async () => {
    expect(
      await service.create({
        name: 'demouser',
        email: 'demo@gmail.com',
        password: 'demo@123',
        role: 'user'
      })
    ).toEqual({
      statusCode: 201,
      message: 'User created successfully',
      data: {
        isActive: true,
        role: 'user',
        password:
          'b$VjwR0Wjf6vTaRjQlsizB5OLY04NJOcRyC/pPLbTPTQnWTDIrBU.Sq',
        email: 'demo@gmail.com',
        name: 'demouser',
        _id: expect.any(Number)
      }
    })
  })


})

正如我在规范文件中强调的那样,UserDocumentusers.entity.ts 文件中定义的类型,userDocument = module.get<UserDocument>(UserDocument) 行中不接受值 UserDocument。

userDocument = module.get<UserDocument>(UserDocument) 必须是
userDocument = module.get<UserDocument>(getModelToken(User.name))
因为您正在尝试获取为 getModelToken(User.name) 提供者

定义的存根

useValue: UserDocument 中你必须使用一些像这样的 stub/mock 对象:https://github.com/jmcdo29/testing-nestjs/blob/6c77b2a5001a48673c77c9659d985a083354579f/apps/sequelize-sample/src/cats/cats.service.spec.ts#L17-L20 因为你试图不使用真实模型。

我解决了我的问题错误。

添加这个导入,它解决了我的错误。

MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])

我可以将实际值添加到数据库中

//users.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing'
import { UsersService } from './users.service'
import { AppConfigModule } from '../config/app-config.module'
import { AppConfigService } from '../config/app-config.service'
import { ConfigModule } from '@nestjs/config'
import { MongooseModule, getModelToken } from '@nestjs/mongoose'
import { User, UserSchema } from './entities/user.entity'
import { isValidObjectId } from 'mongoose'
import { HttpException } from '@nestjs/common'

const testUser = {
  name: 'demouser',
  email: 'demo@gmail.com',
  password: 'demo@123',
  role: 'user'
}
describe('UsersService', () => {
  let service: UsersService

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          cache: true
        }),
        MongooseModule.forRootAsync({
          imports: [AppConfigModule],
          inject: [AppConfigService],
          useFactory: (config: AppConfigService) => ({
            uri: `mongodb://${config.TESTDATABASE_HOST}:${config.TESTDATABSE_PORT}`,
            dbName: config.TESTDATABASE_NAME
          })
        }),
        MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])//-------import model here
      ],
      providers: [UsersService]
    }).compile()

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

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