Как протестировать небольшую функцию, которая сильно зависит от взаимодействия с базой данных? - PullRequest
0 голосов
/ 18 марта 2020

Я создаю серию маршрутов для создания своего рода викторины. Я решил построить его почти как связанный список с каждым элементом в форме, указывающим на элементы next / prev. Я хочу, чтобы у всех были тесты, но я не могу понять, как написать тест для следующего:

    async create(next){

    // check if form already has elements added to it
    const elements = await db.elements.findAll({ where: { form_id: this.formId } });

    // if form already has elements added and next is not provided, append element to the end of the form
    if (elements.length && !next) {
        await this._createAtEnd(elements, next);
    }
    // if next is not the end of the element list, insert element before next element
    else if (elements.length){
        await this._insert(elements, next);
    }

    return db.elements.findAll({ where: { form_id: this.formId } });
  }

  async _insert(elements, next){
      const tempPrevious = elements.filter(el => el.next_element_id === next).pop();
      const tempNext = tempPrevious ? elements.filter(el => el.id === tempPrevious.next_element_id).pop() : null;


      const created =  await db.elements.create({
          form_id: this.formId,
          previous_element_id: tempPrevious ? tempPrevious.id : null,
          next_element_id: next,
      });


      // update the element prior to the newly inserted element
      if (tempPrevious) {
          return Promise.all( [
              tempPrevious.update({ next_element_id: created.id }),
              tempNext.update({ previous_element_id: created.id }),
          ]);
      }

      // element is being inserted at the beginning
      const first =  elements.map(el => el.previous_element_id === null).pop();
      return first.update({ previous_element_id: created.id });
  }

Допустим, я заглушил базу данных (db), чтобы тест выглядел следующим образом следующее:

 it('should create a new element', async () => {
    const formId = 1;
    const next = 2;
    const data = [
      { id: 0, form_id: formId, previous_element_id: null, next_element_id: 1, },
      { id: 1, form_id: formId, previous_element_id: 0, next_element_id: 2, },
      { id: 2, form_id: formId, previous_element_id: 1, next_element_id: null, },
    ];
    data.forEach(el => el.update = function(args){fakeDb.update(this, args)})

    const fakeDb = {
      findAll: async (args) => {
        if (args.where) {
          const keys = Object.keys(args.where);
          return data.filter(el => {
            return keys.filter(key => el[key] === args.where[key]).length;
          });
        }
        return data;
      },
      create: async (item) => {
        item.id = data[data.length - 1].id + 1;
        data.push(item);
        return item;
      },
      update: (obj, args) => {
        const keys = Object.keys(args);
        for (let i=0; i< data.length; i++){
          if (data[i].id === obj.id) {
            keys.forEach(key => data[i][key] = args[key]);
            break;
          }
        }
      },
    };
    sinon.stub(db.elements, 'create').callsFake(fakeDb.create);
    sinon.stub(db.elements, 'findAll').callsFake(fakeDb.findAll);

    const newElement = new NewElement({ formId });
    const created = await newElement.create(next);

    expect...

Глядя на это, я чувствую, что пишу много кода для fakeDb и фактически не тестирую create. Моим первоначальным ощущением было возвращение постоянного значения, например:

const fakeDb = {
      create: Promise.resolve({ id: 1, forms_id: formId, previous_element_id: 0, next_element_id: 2 }),
};

Однако тогда я действительно чувствовал, что тест бесполезен? Функция все равно сможет пройти независимо от того, что я делал внутри. При тестировании принято создавать набор данных, которым вы можете манипулировать, даже если вы тогда создаете кучу методов для эмуляции БД? из этого теста и создайте какую-нибудь вспомогательную функцию, чтобы я не переписывал ее в каждом тесте. Я также не хочу слишком усложнять все это.

...