[узел] [мокко] Глобальные переменные недоступны при тестировании с мокко - PullRequest
4 голосов
/ 02 апреля 2020

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

В моем index.js я загружаю конфигурацию в глобальную переменную следующим образом:

global.env = {};
global.env.config = require('./config/config');
// Create the server ...
server.listen(3000);

module.exports = server;

В каком-то другом контроллере myController.js я обращаюсь к глобальной переменной следующим образом:

var Config = global.env.config

Когда я запускаю ее, используя node index.js, она работает просто отлично.

Но когда я использую mocha с proxyquire для переопределения конфигурации:

describe('myController', function () {
    describe("#myMethod", () => {

        it("must work", (done) => {
             const config = {
                INPUT_FILE_DIR: path.resolve('../ressources/input/')
             }

             const server = proxyquire('../index.js', { './config/config': config })// error in this line
        })
    })
})

У меня возникает ошибка, сообщающая, что myController не может прочитать конфигурацию свойства

Cannot read property 'config' of undefined

Спасибо за вашу помощь

Ответы [ 2 ]

5 голосов
/ 13 апреля 2020

Вот как бы я подошел к этому. Во-первых, я экспортировал бы config как функцию вместо объекта.

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

export const getConfig = () => {
  if(process.env.NODE_ENV==="production"){
    return require('./production.config');
  }
  return require('./default.config');
};

В моем тестовом файле я высмеивал вызов функции, используя sinonjs, как показано ниже.

const configModule = require("./config");
sinon.stub(configModule, "getConfig").returns(require('./e2e.config'));

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

4 голосов
/ 09 апреля 2020

Почему бы просто не перезаписать его новой конфигурацией в вашем тестовом примере.

Например

index.js:

const express = require('express');
const server = express();
const userController = require('./userController');

global.env = {};
global.env.config = require('./config');

server.get('/api/user', userController.getUser);

if (require.main === module) {
  const port = 3000;
  server.listen(port, () => {
    console.log(`HTTP server is listening on http://localhost:${port}`);
  });
}

module.exports = server;

userController.js:

const Config = global.env.config;

const userController = {
  getUser(req, res) {
    res.json(Config.user);
  },
};

module.exports = userController;

config.js:

module.exports = {
  user: { name: 'james' },
};

userController.test.js:

const sinon = require('sinon');

describe('userController', () => {
  describe('#getUser', () => {
    it('should pass', () => {
      global.env = {};
      global.env.config = { user: { name: 'jane' } };
      const userController = require('./userController');
      const mReq = {};
      const mRes = { json: sinon.stub() };
      userController.getUser(mReq, mRes);
      sinon.assert.calledWithExactly(mRes.json, { name: 'jane' });
    });
  });
});

Результаты модульных испытаний с отчетом о покрытии:

  userController
    #getUser
      ✓ should pass (880ms)


  1 passing (893ms)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |     100 |      100 |     100 |     100 |                   
 userController.js |     100 |      100 |     100 |     100 |                   
-------------------|---------|----------|---------|---------|-------------------

ОБНОВЛЕНИЕ

index.js:

// Order is matter, assign config to global firstly, then the controllers can access it.
global.env = {};
global.env.config = require('./config');

const express = require('express');
const server = express();
const userController = require('./userController');

server.get('/api/user', userController.getUser);

if (require.main === module) {
  const port = 3000;
  server.listen(port, () => {
    console.log(`HTTP server is listening on http://localhost:${port}`);
  });
}

module.exports = server;

userController.js и config.js такие же, как указано выше.

index.test.js:

const request = require('supertest');
const proxyquire = require('proxyquire');
const { expect } = require('chai');

describe('60990025', () => {
  it('should get user', (done) => {
    const config = { user: { name: 'jane' } };
    const server = proxyquire('./', {
      './config': config,
    });
    request(server)
      .get('/api/user')
      .expect(200)
      .end((err, res) => {
        if (err) return done(err);
        expect(res.body).to.be.eql({ name: 'jane' });
        done();
      });
  });
});

Результаты тестирования API с отчетом о покрытии:

  60990025
    ✓ should get user (2946ms)


  1 passing (3s)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   81.25 |       50 |      50 |   81.25 |                   
 config.js         |     100 |      100 |     100 |     100 |                   
 index.js          |   72.73 |       50 |       0 |   72.73 | 12-14             
 userController.js |     100 |      100 |     100 |     100 |                   
-------------------|---------|----------|---------|---------|-------------------

исходный код: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/60990025

...