【问题标题】:Nestjs testing - service method returns data when it shouldn'tNestjs 测试 - 服务方法在不应该返回数据时返回
【发布时间】:2020-07-15 02:58:36
【问题描述】:

我正在编写一个模拟在数据库中创建新用户的单元测试。在user.service.add 方法中,我调用findOne 来检查用户是否存在于数据库中。在开发中,这可以正常工作,但在测试中 - findOne 在不应该返回数据时返回数据。

至少我认为不应该。为什么要返回数据?

我的测试

const testUserUsername1 = faker.internet.userName();
const testUserEmail1 = faker.internet.email();
const testUserPassword1 = faker.internet.password();
const testUserName1 = `${faker.name.firstName()} ${faker.name.lastName()}`;

const testUserName2 = `${faker.name.firstName()} ${faker.name.lastName()}`;

// user test object
const testUser = new User(
  testUserName1,
  testUserEmail1,
  testUserPassword1,
  testUserUsername1,
);

describe('UserService', () => {
  let userService: UserService;
  let postService: PostService;
  let likeService: LikeService;
  let userRepository: Repository<User>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        {
          provide: getRepositoryToken(User),
          useClass: Repository,
        },
        {
          provide: getRepositoryToken(User),
          // mocks of all the methods from the User Service
          useValue: {
            save: jest.fn(),
            create: jest.fn().mockReturnValue(testUser),
            find: jest.fn().mockResolvedValue(testUsers),
            findOne: jest.fn().mockResolvedValue(testUser),
            update: jest.fn().mockResolvedValue(testUser),
            delete: jest.fn().mockResolvedValue(true),
          },
        },
        PostService,
        {
          provide: PostService,
          useClass: Repository,
        },
        LikeService,
        {
          provide: LikeService,
          useClass: Repository,
        },
      ],
    }).compile();
    userRepository = module.get<Repository<User>>(getRepositoryToken(User));
    userService = module.get<UserService>(UserService);
    postService = module.get<PostService>(PostService);
    likeService = module.get<LikeService>(LikeService);
  });

it('should be able to create a user', async () => {
    const tempUser = {
      name: testUserName1,
      email: testUserEmail1,
      username: testUserUsername1,
      password: testUserPassword1,
    }
    userRepository.findOne = jest.fn(() => tempUser.username);

    await userService.add(tempUser)
    expect(tempUser).toEqual(testUser);
  });
  afterEach(() => {
    jest.resetAllMocks();
  });
});

user.service.add

  async add(userDto: Partial<UserCreateDTO>): Promise<UserDTO> {
    // get data from args
    const { name, password, username, email } = userDto;

    // check if the user exists in the db
    const userInDb = await this.userRepository.findOne({
      where: { username },
    });

    console.log('username: ', username)
    console.log('userInDb: ', userInDb)

    if (userInDb) {
      throw new HttpException('User already exists', HttpStatus.BAD_REQUEST);
    }

    // create new user 
    const user: User = await this.userRepository.create({
      name,
      password,
      username,
      email,
    });

    // save changes to database
    await this.userRepository.save(user);

    // return user object
    return toUserDto(user);
  }

user.service.add 中的console.log 输出

   console.log src/user/user.service.ts:49
      username: Mayra_Rolfson53
    console.log src/user/user.service.ts:50
      userInDb: User {
        name: 'Albert Kuvalis',
        email: 'Martin_Jacobson@gmail.com',
        username: 'SQT_L6iGKzPVFPI',
        password: 'Mayra_Rolfson53'
      }

抛出错误

    User already exists

      50 |     console.log('userInDb', userInDb)
      51 |     if (userInDb) {
    > 52 |       throw new HttpException('User already exists', HttpStatus.BAD_REQUEST);
         |             ^
      53 |     }

【问题讨论】:

  • 你没有专门为模拟用户存储库定义这种行为吗? ``` findOne: jest.fn().mockResolvedValue(testUser), ```
  • 我想我不是吗?哈哈。如果我不这样做,那么我会得到findOne is not a function.. 如果我想在此之后的另一个测试中向 findOne 发送文本但仅在 this 的情况下我希望 findOne 什么都不返回怎么办?
  • 好的,所以测试的行为完全符合预期 - findOne() 每次调用时都会返回预定义的用户对象。您可能需要更改模拟行为以适应此特定测试的需要。如果这个 .fndOne() 在测试中只被调用一次,并且你需要它返回 null,那么就这样做! findOne: jest.fn().mockResolvedVaue(null)
  • 啊,也可以!相反,我在下面用另一个解决方案写了一个答案,并在其中标记了 u。您也可以将此答案作为解决方案发布!

标签: unit-testing jestjs nestjs


【解决方案1】:

我认为解决方案是在我的 findOne 方法中找到用户时添加返回类型

之前

  async findOne(uid: string): Promise<User> {
    return await this.userRepository.findOne({
      relations: ['posts', 'comments'],
      where: { uid },
    });
  }

之后

  async findOne(uid: string): Promise<User | undefined> {
    return await this.userRepository.findOne({
      relations: ['posts', 'comments'],
      where: { uid },
    });
  }

现在在我的测试中,我希望在我的 findOne 模拟中返回 undefined 而不是 testUser

  it('should be able to create a user', async () => {
    const tempUser = {
      name: testUserName1,
      email: testUserEmail1,
      username: testUserUsername1,
      password: testUserPassword1,
    }
    userRepository.findOne = jest.fn(() => undefined);

    await userService.add(tempUser)
    expect(tempUser).toEqual(testUser);

  });

我的测试现在通过了,但是 我不知道这是否是 TypeScript 或 Nest.js 测试中的最佳实践。如果有人有更好的建议,请随时发布!

感谢@amakhrov 在 cmets 中的提示!

【讨论】:

    猜你喜欢
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 2013-12-28
    • 1970-01-01
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多