как я могу имитировать запрос функции при попытке протестировать метод

#sinon

#sinon

Вопрос:

//user.dal

У меня есть эти два метода в user.dal, и я пытаюсь протестировать метод1, но внутри него есть запрос, вызываемый function1 (я хочу подделать результат этого) Я использую sinon.stub

 export async function function1(id) {
      try {
        const result1 = await User.findOne({ _id: id });
        return result1;
      } catch (error) {
        throw new Error('invalid user');
      }
    }

export async function method1(id, date) {
  const request1 = await function1(id); // this is not faking its results
  const request2 = await function2(request1); // this need to fake the results also
  return request2;
}
  

//user.test

 describe.only('get all information ', () => {
    const id = '5c842bd3cf058d36711c6a9e';
    const user = {
      _id: '5c76f49e6df2131fe23a100a',
    };
    const date = '2019-03-09';
    let spyFunction1;
    beforeEach(async () => {
      spyFunction1 = sinon.stub(userDal, 'function1').returns('this is my result');
    });

    afterEach(async () => {
      await userModel.deleteOne({ _id: id });
      spyFunction1.restore();
    });

    it('Should get.', async () => {
      const result = await userDal.function1(id);
      console.log('this is working well', result);

      const badResult = await userDal.method1(id, date);
      console.log('-->>>', badResult); // when its call to method 1, its calling to the method and not using the mock that I impemented before
    });
  });
  

Ответ №1:

Из import документа:

Оператор static import используется для импорта привязок, которые экспортируются другим модулем.

Итак, когда вы делаете это:

 import * as userDal from './user.dal';
  

результатом является то, что userDal содержит привязки ко всему, что экспортируется user.dal модулем.


Затем, когда вы делаете это:

 sinon.stub(userDal, 'function1').returns('this is my result');
  

function1 привязка заменяется на stub , которая возвращает 'this is my result' .

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


Итак, когда выполняется эта строка:

 const result = await userDal.function1(id);
  

он вызывает модуль export для function1 (который был заглушен), поэтому результат 'this is my result' .


С другой стороны, когда выполняется эта строка:

 const badResult = await userDal.method1(id, date);
  

он вводит method1 , который затем запускает эту строку:

 const request1 = await function1(id); // this is not faking its results
  

для которого не вызывается модуль export function1 , он вызывается function1 напрямую.


Чтобы иметь возможность заглушки function1 и function2 внутри method1 , вы должны вызвать их модуль экспорта вместо того, чтобы вызывать их напрямую.


Для Node.js модуля шаблон выглядит следующим образом:

 const function1 = async function (id) { /* ... */ }
const function2 = async function (id) { /* ... */ }

const method1 = async function (id, date) {
  const request1 = await exports.function1(id);  // call the module export
  const request2 = await exports.function2(request1);  // call the module export
  return request2;
}

exports.function1 = function1;
exports.function2 = function2;
exports.method1 = method1;
  

Для модуля ES6 шаблон аналогичен. Обратите внимание, что «Модули ES6 автоматически поддерживают циклические зависимости», поэтому мы можем import вернуть модуль в себя, чтобы получить доступ к экспорту модуля:

 import * as userDal from 'user.dal';  // import module into itself

export async function function1(id) { /* ... */ }
export async function function2(id) { /* ... */ }

export async function method1(id, date) {
  const request1 = await userDal.function1(id);  // call the module export
  const request2 = await userDal.function2(request1);  // call the module export
  return request2;
}
  

Если вы последуете этому шаблону и вызовете модуль exports для function1 и function2 изнутри method1 , то когда вы замените модуль exports для этих двух функций заглушками, заглушки будут вызываться при вашем вызове method1 .

Комментарии:

1. Да, спасибо за совет, я перешел в другой файл и использую импорт и экспорт, и это работает хорошо. Большое вам спасибо

Ответ №2:

Я думаю, вам следует создать сигнатуру метода следующим образом: method1(id, date, function1, function2) . По сути, вы бы передавали функцию 1 в качестве параметра. Тогда в вашем тесте вы можете вместо этого передать имитируемую функцию или заглушку, чтобы иметь возможность ее протестировать.

 export async function function1(id) {
      try {
        const result1 = await User.findOne({ _id: id });
        return result1;
      } catch (error) {
        throw new Error('invalid user');
      }
    }

export async function method1(id, date, function1, function2) {
  const request1 = await function1(id); 
  const request2 = await function2(request1);
  return request2;
}