Модульное тестирование express. js маршрута с помощью sinon - PullRequest
1 голос
/ 29 апреля 2020

Я учу express и Синон (трудный путь :)). Я хотел бы протестировать следующий код:

//  ./routers/root.js

var express = require('express');
var router = express.Router();

router
  .route('/')
  .get(function(req, res) {
    res.writeHead(200, {'Content-Type': 'application/json'});
    res.write(JSON.stringify({Application: "NodeTours", Version: "2.0.0", Host: host, Port: port}));
    res.end();
  });

module.exports = router;

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

//   ./test/test.js

var sinon = require('sinon')
var expect = require('chai').expect

describe('Routers', function() {

  context('/', function() {
    var rootRouter = require('../routers/root')
    var res = {Application: "NodeTours", Version: "2.0.0", Host: 'host', Port: 'port'};
    it('should call / router', function() {
      rootRouter.route('/').get(null, res);
      // TODO: expect...
    })
  })
})

Не удается с:

  Routers
    /
      1) should call / router


  0 passing (4ms)
  1 failing

  1) Routers
       /
         should call / router:
     Error: Route.get() requires a callback function but got a [object Null]
      at Route.<computed> [as get] (node_modules/express/lib/router/route.js:202:15)
      at Context.<anonymous> (test/test.js:10:29)
      at processImmediate (internal/timers.js:456:21)

Я пробовал несколько уроков без успеха. Буду признателен за любые указания на то, как мой код может быть проверен модулем. Или как настроить мой код так, чтобы модульное тестирование было легче / возможно.

Мой главный сервер приложений. js файл для контекста и ссылки (удаленный код не подходит для этого вопроса)

//   ./server.js
// npm pacakages
var express = require('express');
var bodyParser = require('body-parser');

// app imports
var { rootRouter } = require('./routers');
// other cut out

//globals
app = express();
app.use(bodyParser.json());
app.use('/', rootRouter);
// other cut out

// Set up Mongo DB connection
// code to st up db connection

// Start server (only if connection to DB established)
var server = MongoClient(url, { useUnifiedTopology: true, poolSize: 10 }).connect().then(client => {
  const dbo = client.db(dbName);

  // some init code cut out

  // make connection available
  app.locals.dbo = dbo;

  // start server
  app = app.listen(process.env.PORT || 7777, function () {
    host = require('os').hostname();
    port = "7777";
    logger.verbose("Startup: NodeTours listening at http://%s:%s", host, port)
  });
}).catch(error => {
  logger.error("Startup: Couldn't connect to the DB. The app will exit")
  logger.error("  Error: " + error)
  process.exit();
  }
);

Ответы [ 2 ]

0 голосов
/ 30 апреля 2020

На данный момент я сделал следующие изменения:

1) изменил код маршрутизатора, чтобы переместить логи контроллера / обработчика c за пределы

// ./routers/root
var express = require('express');
var router = express.Router();

var rootController = require('../controllers/root')

router
  .route('/')
  .get(rootController.root_get);

module.exports = router;

2) добавил контроллер / Обработчик logi c в отдельном файле

// ./controllers/root
var logger = require('../utilities/loggers')

exports.root_get = function(req, res) {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.write(JSON.stringify({Application: "NodeTours", Version: "2.0.0", Host: host, Port: port}));
  res.end();
}

3) реализовал тест следующим образом:

var sinon = require('sinon')
var expect = require('chai').expect

describe('Controllers', function() {
  context('/', function() {
    var root = require('../controllers/root')  
    it('should call GET / controller', function() {
      var res;
      spy = root.root_get = sinon.spy()
      root.root_get(null, res);
      expect(spy.calledOnce).to.equal(true);
    })
  })
})

, который выполняет OK:

  Controllers
    /
      ✓ should call GET / controller


  1 passing (5ms)

Это только частично решает мою первоначальную проблему, поскольку я хотел, чтобы маршрутизатор logi c был протестирован. Я разместил отдельный вопрос для этой части в другой теме.

0 голосов
/ 30 апреля 2020

В вашем тестовом примере вы пытаетесь вызвать ваш обработчик GET напрямую:

it('should call / router', function() {
  rootRouter.route('/').get(null, res);
  // TODO: expect...
})

Но appRouter.route ('/'). Get () - это метод, предназначенный установить обработчик запроса, чтобы не вызывать его. Вот почему вы получаете сообщение об ошибке:

Ошибка: Route.get () требует функцию обратного вызова, но получил [объект Null]

, то есть вы передаете null для того, что вы считаете параметром запроса, но Express ожидает, что это будет обработчик метода (обратного вызова).

Обычно я буду определять свои обработчики как неанонимные функции:

function rootHandler(req, res) {
    res.writeHead(200, {'Content-Type': 'application/json'});
    res.write(JSON.stringify({Application: "NodeTours", Version: "2.0.0", Host: host, Port: port}));
    res.end();
}

router
  .route('/')
  .get(rootHandler);

... и тогда модульные тесты могут просто вызывать функцию напрямую, а не с go по Express (потому что обычно мы заинтересованы в тестировании нашего собственного кода, а не фреймворка):

it('should do something with root handler', function() {
  rootHandler(null, res);
  // TODO: expect...
})

Если вы действительно хотите протестировать логи маршрутизации c, тогда хорошим вариантом будет использование supertest, как указано в комментариях.

...