Фабрика пытается создать два объекта с одинаковыми свойствами - PullRequest
0 голосов
/ 03 мая 2020

Я пишу тесты для express приложения, которое реализует пользовательский CRUD. Перед написанием интеграционных тестов я создал фабрику, которая создавала бы пользователей для тестов:

factories.js

import faker from 'faker';
import { factory } from 'factory-girl';

import User from '../../src/app/models/User';

factory.define('User', User, {
  name: faker.name.firstName(),
  email: faker.internet.email(),
  password: faker.internet.password(),
  admin: false,
});

export default factory;

Приятно. Теперь, когда мне нужно было создать пользователя для тестов, мне просто нужно было бы использовать factory.create(), верно? Неправильно. В одном из тестовых наборов мне нужны два пользователя: один - администратор, а другой - нет. Итак, я написал эту настройку / разрыв:

let user, admin; 

const createUsers = async () => {
  // Runs ok 
  user = await factory.create('User');

  // Error
  admin = await factory.create('User', { admin: true });
};

const removeUsers = async () => {
  await user.remove();
  await admin.remove();
};

beforeAll(async () => {
  await createUsers();
});

afterAll(async () => {
    await removeUsers();
    mongoose.connection.close();
});

user = await factory.create(...) работает нормально, но admin = await factory.create(...) вызывает MongoError: E11000 duplicate key error collection.

Это потому, что фабрика пытается создать пользователя с адрес электронной почты, который уже используется (адрес электронной почты уникален для пользователя модели). Я мог бы гарантировать, что этого не произойдет, передав специальное c электронное письмо методу create таким же образом, как я передал admin: true, но это не имело бы большого смысла, так как я создал фабрику, чтобы избежать подобных проблем.

Не могли бы вы, ребята, указать, что я здесь не так делаю? Я думаю, это как-то связано с тем, как я определил свою фабрику. Заранее спасибо.

РЕДАКТИРОВАТЬ: Как предложено, я исправил это с помощью factory.sequence.

factory.define('User', User, {
  name: factory.sequence('User.name', () => faker.name.firstName()),
  lastName: factory.sequence('User.lastName', () => faker.name.lastName()),
  email: factory.sequence('User.email', () => faker.internet.email()),
  password: factory.sequence('User.password', () => faker.internet.password()),
  redefinePassword: false,
  admin: false,
});

1 Ответ

1 голос
/ 03 мая 2020

Хотя faker.inte rnet .email () будет создавать новое поддельное электронное письмо при каждом его вызове, вы будете вызывать его только один раз при определении объекта шаблона для фабрики. Посмотрите в API factory.sequence способ заставить фабрику запускать некоторый код для каждого создаваемого объекта https://www.npmjs.com/package/factory-girl#defining -фактуры

Или просто передать функцию faker.inte rnet .email, без (), и я думаю, что factory-girl будет также вызывать эту функцию каждый раз, вы также можете сделать так, чтобы ваш вызов define принял функцию, которая возвращает этот объект (после вызова faker.inte rnet .email ()) так много вариантов!

...