Модульное тестирование в Loopback с мокко, синон и чай - PullRequest
0 голосов
/ 09 сентября 2018

Я пытаюсь начать модульное тестирование своих пользовательских методов в Loopback. Сам метод очищает все пользовательские данные, задающие параметр.

module.exports = function(User) {
  User.clearData = async function(options) {
    const cityId = options.accessToken.cityId;

    const deleteUserData = () => {
      return User.destroyAll({cityId: cityId}, options).catch(error => {
        console.log('Error deleting user', error);
        throw error;
      });
    };

    await deleteUserData();
  };
};

То, что я сделал раньше, выглядит примерно так:

const sinon = require('sinon');
const {expect} = require('chai');

const clearDataUser = require('../clear-data');

describe('User clear data', ()=>{
  let spy,
    User;

  const options = {
    accessToken: {
      cityId: 1,
    },
  };

  beforeEach(()=>{
    spy = sinon.spy();
    User = {
      destroyAll: spy,
    };
  });

  it('should call destroyAll', () => {
    clearDataUser(User);
    User.destroyAll({cityId: options.accessToken.cityId}, options);
    expect(spy.callCount).to.eq(1);
  });
});

Это будет проверять только то, что destroyAll вызывается. Есть ли способ проверить условие catch? Я также использую async/await, так можно ли это учитывать? _____________________________________ _____________________________________ EDIT

Я немного изменил его, чтобы он выглядел так:

  it('should call destroyAll', async() => {
    clearDataUser(User);
    const deleteUserData = () => {
      return User.destroyAll({cityId: options.accessToken.cityId}, options);
    };

    await deleteUserData();
    expect(spy.callCount).to.eq(1);
  });

Однако, если я попытаюсь добавить .catch(error => { expect(error).to.not.equal('undefined'); });, я получу TypeError: Cannot read property 'catch' of undefined

1 Ответ

0 голосов
/ 11 сентября 2018

При чтении кода я обнаружил некоторые области, которые можно улучшить. Для исходного кода мы можем удалить функцию deleteUserData. Кроме того, каково ваше намерение изменить объект User, добавив User.clearData?

Это улучшение, которое я сделал.

// clear-data.js

module.exports = function(User) {
  const clearData = function(options) { // no need `async`
    const cityId = options.accessToken.cityId;

    // just return User.destroyAll directly
    return User.destroyAll({cityId: cityId}, options).catch(error => {
      console.log('Error deleting user', error);
      throw error;
    });
  };

  return {
    clearData // this is the function that we should test 
  }
};

И для теста, я не уверен, почему мы тестируем User.destroyAll, так как я ожидаю, что мы тестируем здесь функцию clearData. Мы должны заглушить User.destroyAll, чтобы выполнить обещание или отклонить его (так что catch будет выполнен).

Sinon имеет метод resolves и rejects, который мы можем использовать. Ссылка: https://sinonjs.org/releases/v2.0.0/stubs/

const sinon = require('sinon');
const {expect} = require('chai');

const src = require('../clear-data');

describe('User clear data', () => {
  let stubDestroyAll,
      User;

  const options = {
    accessToken: {
      cityId: 1,
    },
  };

  beforeEach(()=>{
    stubDestroyAll = sinon.stub(); // mock this so we can resolve or reject the method 
  });

  afterEach(() => {
    sinon.restore();
  });

  it('should call destroyAll', async () => {
    User = {
      destroyAll: stubDestroyAll.resolves(), 
    };
    const func = src(User);    
    await func.clearData(options);
    expect(stubDestroyAll.callCount).to.eq(1);
  });

  it('should catch error', async () => {
    User = {
      destroyAll: stubDestroyAll.rejects(), // reject so it will go to catch
    };
    const func = src(User);

    try {
      await func.clearData(options);            
      expect(true).to.be(false); // extra guard if it doesn't go to catch, the test will fail
    } catch(err) {
      expect(stubDestroyAll.callCount).to.eq(1);      
    }
  });
});

Надеюсь, это поможет.

...