Jest - фиктивная функция update () - PullRequest
1 голос
/ 07 февраля 2020

Я пытаюсь смоделировать вызов update(), но продолжаю возвращать одно и то же значение, которое передаю.

Я полагаю, это происходит потому, что у меня нет подключенной базы данных, а Jest издевается над поведением .

Используя Почтальон, я могу убедиться, что PUT действительно обновляет пользователя в базе данных.

Как я могу смоделировать функцию обновления в модульном тесте с использованием jest?

user.entity.ts


@Entity('users')
export class User {
  @PrimaryGeneratedColumn('uuid') user_id: string;
  @Column('text') name: string;
  @OneToMany(
    type => Post,
    post => post.user,
    {
      eager: true,
    },
  )
  posts: Post[];
  @OneToMany(
    type => Comment,
    comment => comment.user,
  )
  comments: Comment[];

  constructor(name?: string, posts?: []);
  constructor(name?: string) {
    this.name = name || '';
  }
}

user.service.ts

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @Inject(forwardRef(() => PostService))
    private postService: PostService,
  ) {}

  /**
   * Create a new user
   * @param data Object
   */
  async add(data: Partial<UserDTO>): Promise<User> {
    // create object with new user props
    const newUser = await this.userRepository.create(data);
    await this.userRepository.save(newUser);
    return newUser;
  }

 /**
   * Update an existing user
   * @param data Object
   */
  async edit(user_id: string, data: Partial<UserDTO>): Promise<User> {
    await this.userRepository.update({ user_id }, data);
    return this.userRepository.findOne({ user_id });
  }

  /**
   * Return one user
   */
  async findOne(user_id: string): Promise<User> {
    return await this.userRepository.findOne({
      relations: ['posts', 'comments'],
      where: { user_id },
    });
  }

... more methods

}

user.service.spe c .ts

import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import * as faker from 'faker';
import { PostService } from '../post/post.service';

// test data for user
const testUserName1 = `${faker.name.firstName()} ${faker.name.lastName()}`;

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

// user test object
const testUser = new User(testUserName1);
const testUser2 = new User(testUserName2);

// users test array
const testUsers = [testUser, testUser2];

// mock of Post Service class
// required as these two models are related
class PostServiceMock extends PostService {}
/**
 * User Model Unit Test
 */
describe('UserService', () => {
  let userService: UserService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        {
          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),
          },
        },
        {
          provide: PostService,
          useValue: PostServiceMock,
        },
      ],
    }).compile();

    userService = module.get<UserService>(UserService);
  });


  it('should be able to update a user', async () => {
    const newUser = await userService.add({
      name: testUserName1,
    });

    const updatedUserName = `${faker.name.firstName()} ${faker.name.firstName()}`;
    const updatedUser = await userService.edit(newUser.user_id, {
      name: updatedUserName,
    });

    expect(updatedUser).not.toBe(newUser);
  });

  afterEach(() => {
    jest.resetAllMocks();
  });
});

1 Ответ

1 голос
/ 08 февраля 2020

Когда вы издеваетесь над подключением к базе данных, вам нужно посмотреть, что возвращают ваши фиктивные функции. После проведенного вами теста обновлений, давайте go пройдем этот шаг за шагом:

const newUser = await userService.add({name: testUser1});

В соответствии с вашим сервисным кодом, userService.add запускает userRepostiory.create() и userRepository.save(). save - это всего лишь метод с заглушкой, поэтому давайте посмотрим на create. Поскольку мы предоставляем макет, мы посмотрим, что макет возвращает

create: jest.fn().mockReturnValue(testUser)

Так что теперь мы знаем, что каждый раз, когда мы называем userRepostiory.create(), testUser будет возвращено. Теперь

const newUser = testUser

по сути является заменой кода. Двигаясь дальше, мы получаем подделку updateUserName, которую мы генерируем, за которой довольно легко следить. Затем мы запускаем наш userService.edit(), поэтому давайте посмотрим на это

async edit(user_id: string, data: Partial<UserDTO>): Promise<User> {
  await this.userRepository.update({ user_id }, data);
  return this.userRepository.findOne({ user_id });
}

Итак, сначала мы запускаем userRepository.update(), а затем userRepository.findOne() и, пока мы все еще дразнимся userRepository, давайте посмотрим на эти насмешки. В частности, findOne, поскольку мы ничего не делаем с возвращаемым значением update.

update: jest.fn().mockResolvedValue(testUser)

Так что update также возвращает testUser. Теперь, если мы заменим наш тестовый код на фиктивную подстановку:

const updateUser = await Promise.resolve(testUser)

или, проще,

const updateUser = testUser

Ваше утверждение тогда будет

expect(udpateUser).not.toBe(newUser)

, и с подстановкой мы есть

expect(testUser).not.toBe(testUser)

И вот, есть проблема. Поскольку макеты create() и findOne() возвращают одно и то же значение и один и тот же объект, ваш пользователь всегда будет одинаковым до и после обновления! Чтобы обойти это, одну вещь, которую вы можете сделать, это смоделировать функцию, чтобы иметь одноразовое значение разрешения, которое отличается, например, так:

const findSpy = jest.spyOn(userRepo, 'findOne').mockResolvedValueOnce(someUpdatedUser)

Для этого вам потребуется получить ссылку на ваш UserRepository просто как и вы за UserService, но в остальном дайте вам свободу сделать утверждение, которое вы ожидаете.

...