invoke get programatically express router для целей тестирования [дублировать]

Итак, есть опция macro @Tsyvarev, которая была первоначально предложена здесь здесь :

# overwrite install() command with a dummy macro that is a nop
macro (install)
endmacro ()

# configure build system for external libraries
add_subdirectory(external)

# replace install macro by one which simply invokes the CMake
install() function with the given arguments
macro (install)
  _install(${ARGV})
endmacro(install)

Примечание ${ARGV} и ${ARGN} совпадают, но документы в настоящее время предложите использовать ${ARGN}. Также тот факт, что макро-переписывание добавляет _ к исходному имени макроса, не документируется, но это по-прежнему поведение. См. Код здесь .

Однако , я никогда не получил вышеуказанный код для правильной работы. Действительно, действительно странные вещи и часто называет install() дважды.

Альтернатива - также недокументированная - использовать EXCLUDE_FROM_ALL:

add_subdirectory(external EXCLUDE_FROM_ALL)

Согласно некоторым комментариям, которые я нашел где-то, это отключает install() для этого подкаталога. Я думаю, что он действительно делает EXCLUDE_FROM_ALL по умолчанию для всех команд install(), которые также, вероятно, делают то, что вы хотите. Я действительно не тестировал его, но стоит того.

83
задан JamesEggers 1 March 2012 в 16:38
поделиться

7 ответов

Измените свой объект ответа:

var response = {
    viewName: ""
    , data : {}
    , render: function(view, viewData) {
        this.viewName = view;
        this.data = viewData;
    }
};

И он будет работать.

20
ответ дан Linus Gustav Larsson Thiel 19 August 2018 в 09:51
поделиться
  • 1
    Благодарю. Знал, это было что-то простое. – JamesEggers 1 March 2012 в 16:41
  • 2
    Это модуль тестирования обработчика запросов, а не маршрута. – Jason Sebring 22 May 2018 в 14:50

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

Таким образом, ваша логика приложения должна быть в отдельных модулях, которые могут быть require d и проверены модулем, и имеют минимальную зависимость от классов Express Request и Response как таковых.

Затем в обработчиках запросов вам нужно вызвать соответствующие методы вашей основной логики классы.

Я приведу пример, как только закончу реструктуризацию моего текущего приложения!

Я думаю, что-то вроде this? (Не стесняйтесь fork the gist или comment, я все еще изучаю это).

Изменить

Вот крошечный пример, встроенный. См. gist для более подробного примера.

/// usercontroller.js
var UserController = {
   _database: null,
   setDatabase: function(db) { this._database = db; },

   findUserByEmail: function(email, callback) {
       this._database.collection('usercollection').findOne({ email: email }, callback);
   }
};

module.exports = UserController;

/// routes.js

/* GET user by email */
router.get('/:email', function(req, res) {
    var UserController = require('./usercontroller');
    UserController.setDB(databaseHandleFromSomewhere);
    UserController.findUserByEmail(req.params.email, function(err, result) {
        if (err) throw err;
        res.json(result);
    });
});
16
ответ дан Adowrath 19 August 2018 в 09:51
поделиться

Чтобы выполнить модульное тестирование вместо тестирования интеграции, я высмеивал объект ответа обработчика запроса.

/* app.js */
import endpointHandler from './endpointHandler';
// ...
app.post('/endpoint', endpointHandler);
// ...

/* endpointHandler.js */
const endpointHandler = (req, res) => {
  try {
    const { username, location } = req.body;

    if (!(username && location)) {
      throw ({ status: 400, message: 'Missing parameters' });
    }

    res.status(200).json({
      location,
      user,
      message: 'Thanks for sharing your location with me.',
    });
  } catch (error) {
    console.error(error);
    res.status(error.status).send(error.message);
  }
};

export default endpointHandler;

/* response.mock.js */
import { EventEmitter } from 'events';

class Response extends EventEmitter {
  private resStatus;

  json(response, status) {
    this.send(response, status);
  }

  send(response, status) {
    this.emit('response', {
      response,
      status: this.resStatus || status,
    });
  }

  status(status) {
    this.resStatus = status;
    return this;
  }
}

export default Response;

/* endpointHandler.test.js */
import Response from './response.mock';
import endpointHandler from './endpointHander';

describe('endpoint handler test suite', () => {
  it('should fail on empty body', (done) => {
    const res = new Response();

    res.on('response', (response) => {
      expect(response.status).toBe(400);
      done();
    });

    endpointHandler({ body: {} }, res);
  });
});

Затем, чтобы достичь интеграционного тестирования, вы можете высмеять свой endpointHandler и вызвать конечную точку с помощью Supertest .

1
ответ дан fxlemire 19 August 2018 в 09:51
поделиться

Мне тоже было интересно, но специально для модульных тестов, а не для интеграционных тестов. Это то, что я делаю прямо сейчас,

test('/api base path', function onTest(t) {
  t.plan(1);

  var path = routerObj.path;

  t.equals(path, '/api');
});


test('Subrouters loaded', function onTest(t) {
  t.plan(1);

  var router = routerObj.router;

  t.equals(router.stack.length, 5);
});

Где routerObj - это просто {router: expressRouter, path: '/api'}. Затем я загружаю в подпрограммы с помощью var loginRouterInfo = require('./login')(express.Router({mergeParams: true}));, а затем экспресс-приложение вызывает функцию init, принимающую в экспресс-маршрутизаторе параметр. Затем initRouter вызывает router.use(loginRouterInfo.path, loginRouterInfo.router); для монтирования подпроцессора.

Подпроцессор может быть протестирован с помощью:

var test = require('tape');
var routerInit = require('../login');
var express = require('express');
var routerObj = routerInit(express.Router());

test('/login base path', function onTest(t) {
  t.plan(1);

  var path = routerObj.path;

  t.equals(path, '/login');
});


test('GET /', function onTest(t) {
  t.plan(2);

  var route = routerObj.router.stack[0].route;

  var routeGetMethod = route.methods.get;
  t.equals(routeGetMethod, true);

  var routePath = route.path;
  t.equals(routePath, '/');
});
0
ответ дан Marcus Nielsen 19 August 2018 в 09:51
поделиться
  • 1
    Это выглядит действительно интересно. Есть ли у вас больше примеров недостающих частей, чтобы показать, как все это сочетается? – cjbarth 3 August 2016 в 20:29

Самый простой способ проверить HTTP с помощью выражения - это украсть HTTP-помощник TJ

I лично использовать свой помощник

it("should do something", function (done) {
    request(app())
    .get('/session/new')
    .expect('GET', done)
})

Если вы хотите специально протестировать свой объект маршрута, то выполните правильные mocks

describe("Default Route", function(){
    it("should provide the a title and the index view name", function(done){
        routes.index({}, {
            render: function (viewName) {
                viewName.should.equal("index")
                done()
            }
        })
    })
})
19
ответ дан Raynos 19 August 2018 в 09:51
поделиться
  • 1
    вы могли бы исправить ссылку «помощник»? – Nicholas Murray 23 October 2012 в 14:49
  • 2
    @NicholasMurray test-server – Raynos 23 October 2012 в 21:25
  • 3
    Похоже, что более современный подход к тестированию модулей HTTP - использовать supertest от Visionmedia. Также кажется, что HTTP-помощник TJ развился, чтобы добиться успеха. – Akseli Palén 26 March 2013 в 21:17
  • 4
    supertest на github можно найти здесь – Brandon 21 June 2013 в 18:48
  • 5
    К сожалению, это интеграционное тестирование, а не модульное тестирование. – Luke H 3 August 2014 в 16:55

Как было рекомендовано в комментариях другими, похоже, канонический способ тестирования контроллеров Express через supertest .

Примерный пример может выглядеть так:

describe('GET /users', function(){
  it('respond with json', function(done){
    request(app)
      .get('/users')
      .set('Accept', 'application/json')
      .expect(200)
      .end(function(err, res){
        if (err) return done(err);
        done()
      });
  })
});

Потенциал: вы можете протестировать весь свой стек за один раз.

Даунсайд: он чувствует и действует как тестирование интеграции.

31
ответ дан Rich Apodaca 19 August 2018 в 09:51
поделиться
  • 1
    Мне это нравится, но есть ли способ утверждать имя_имя (как в исходном вопросе) - или мы должны были бы утверждать о содержании ответа? – Alex 3 December 2013 в 01:51
  • 2
    Я согласен с вашим недостатком, это не модульное тестирование. Это зависит от интеграции всех ваших подразделений для проверки URL-адресов вашего приложения. – Luke H 3 August 2014 в 16:55
  • 3
    Я думаю, что законно говорить, что «маршрут» на самом деле это integration, и, возможно, маршруты тестирования должны быть оставлены на интеграционных тестах. Я имею в виду, что функциональность маршрутов, соответствующих их определенным обратным вызовам, предположительно уже проверена express.js; любая внутренняя логика для получения конечного результата маршрута, в идеале должна быть модульной вне его, и эти модули должны быть проверены на единицу. Их взаимодействие, т. Е. Маршрут, должно быть проверено на интеграцию. Согласитесь? – Aditya M P 6 March 2017 в 13:33
  • 4
    Это сквозное тестирование. Без сомнений. – kgpdeveloper 3 January 2018 в 04:33

, если модульное тестирование с экспресс-4 отмечает этот пример из gjohnson :

var express = require('express');
var request = require('supertest');
var app = express();
var router = express.Router();
router.get('/user', function(req, res){
  res.send(200, { name: 'tobi' });
});
app.use(router);
request(app)
  .get('/user')
  .expect('Content-Type', /json/)
  .expect('Content-Length', '15')
  .expect(200)
  .end(function(err, res){
    if (err) throw err;
  });
3
ответ дан zbr 19 August 2018 в 09:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: