Nestjs unit test: TypeError: this.userModel.findById(...).exec is not a function

Nestjs unit test: TypeError: this.userModel.findById(...).exec is not a function

使用 nestjs 框架和使用猫鼬执行 CRUD 操作的存储库 class 我们有一个简单的 users.repository.ts 文件,如下所示:

@Injectable()
export class UserRepository {
  constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}
  async create(createUserInput: CreateUserInput) {
      const createdUser = new this.userModel(createUserInput);
      return await createdUser.save();
    }
  }

  async findById(_id: MongooseSchema.Types.ObjectId) {
    return await this.userModel.findById(_id).exec();
  }

并且在服务器启动时它可以正常工作。
考虑这个 users.repository.spec 文件:

import { Test, TestingModule } from '@nestjs/testing';
import { getModelToken } from '@nestjs/mongoose';
import { Model } from 'mongoose';

// User is my class and UserDocument is my typescript type
// ie. export type UserDocument = User & Document; <-- Mongoose Type
import { User, UserDocument } from '../domain/user.model';
import { UserRepository } from './users.repository';
//import graphqlScalars from 'graphql-scalar-types';

describe('UsersRepository', () => {
  let mockUserModel: Model<UserDocument>;
  let mockRepository: UserRepository;

  beforeAll(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        {
          provide: getModelToken(User.name),
          useValue: Model, // <-- Use the Model Class from Mongoose
        },
        UserRepository,
        //graphqlScalars,
      ],
    }).compile();
    // Make sure to use the correct Document Type for the 'module.get' func
    mockUserModel = module.get<Model<UserDocument>>(getModelToken(User.name));
    mockRepository = module.get<UserRepository>(UserRepository);
  });

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

  it('should return a user doc', async () => {
    // arrange
    const user = new User();
    const userId = user._id;
    const spy = jest
      .spyOn(mockUserModel, 'findById') // <- spy 
      .mockResolvedValue(user as UserDocument); // <- set resolved value
    // act
    await mockRepository.findById(userId);
    // assert
    expect(spy).toBeCalled();
  });
});

所以我的问题是: 对于 should return a user doc 测试,我得到 TypeError: metatype is not a constructor,我猜

.mockResolvedValue(user as UserDocument); 应该是固定的。 Note:graphql 用于 API 的查询,我不知道是否应该提供标量,如果我取消对标量的注释, expect(mockRepository).toBeDefined(); 测试将不再通过

所以任何修复测试的想法都会受到赞赏。

要处理链式 .exec 我们应该通过 mockReturnThis():

定义它
static findById = jest.fn().mockReturnThis();

我需要通过 new 调用构造函数,所以我更喜欢以这种方式定义模拟 class:

class UserModelMock {
  constructor(private data) {}
  new = jest.fn().mockResolvedValue(this.data);
  save = jest.fn().mockResolvedValue(this.data);
  static find = jest.fn().mockResolvedValue(mockUser());
  static create = jest.fn().mockResolvedValue(mockUser());
  static remove = jest.fn().mockResolvedValueOnce(true);
  static exists = jest.fn().mockResolvedValue(false);
  static findOne = jest.fn().mockResolvedValue(mockUser());
  static findByIdAndUpdate = jest.fn().mockResolvedValue(mockUser());
  static findByIdAndDelete = jest.fn().mockReturnThis();
  static exec = jest.fn();
  static deleteOne = jest.fn().mockResolvedValue(true);
  static findById = jest.fn().mockReturnThis();
}