Подтвердить что ты не робот

Как протестировать API Node, который использует аутентификацию JWT (с именем пользователя, чтобы получить токен)

TL; DR - Каков способ тестирования ресурсов в Node API (Express), который использует JWT для аутентификации, при этом сам токен предоставляется только для имени пользователя/пароля?

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

Используемые технологии

  • Я написал API в Node, используя Экспресс.
  • Mongo - это база данных.
  • Mongoose используется как ODM. Пакет
  • jsonwebtoken используется для создания/проверки токенов.
  • Паспорт используется для простого добавления промежуточных программ для проверки подлинности пользователя в качестве промежуточного программного обеспечения Express на маршрутах.

Информация об API

API имеет различные ресурсы - особенности, которые важны для этого запроса, но позволяют просто притворяться вездесущим приложением Todo для простоты.

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

API использует JWT для аутентификации через различные конечные точки ресурсов. Сам токен содержит уникальный идентификатор пользователя, который хранится в ресурсе в базе данных Mongo. Чтобы получить сам токен, пользователь должен сначала зарегистрироваться (который возвращает токен), а затем войти, чтобы получить новый токен.

Притворите код.

Я собираюсь упростить приведенный ниже код и не использовать никаких конфигураций среды и т.д.

app.js

var express = require('express');
var app = express();
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var passport = require('passport');

mongoose.connect('mongodb://localhost/somedatabasename');

app.set('port', process.env.PORT || 3000);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.use(passport.initialize());
// ... Passport JWT Strategy goes here - omitted for simplicity ...

var userRouter = require('./api/users/routes');
app.use('/users', userRouter);
var todoRouter = require('./api/todos/routes');
app.use('/todos', todoRouter);

app.listen(app.get('port'), function() {
  console.log('App now running on http://localhost:' + app.get('port'));
});

./апи/Todos/routes.js

var router = require('express').Router();
var controller = require('./controller');
var passport = require('passport');

router.route('/')
  .all(passport.authenticate('jwt', { session: false}))
  .get(controller.getAll)
  .post(controller.create);

router.route('/:id')
  .all(passport.authenticate('jwt', { session: false}))
  .get(controller.getOne)
  .put(controller.update)
  .delete(controller.delete);

module.exports = router;

./API/пользователей/routes.js

var router = require('express').Router();
var controller = require('./controller');
var passport = require('passport');

router.route('/')
  // User signup
  .post(controller.create);

router.route('/me')
  // User Login
  .post(passport.authenticate('local', { session: false}), controller.login)
  // Get current user data
  .get(passport.authenticate('jwt', { session: false}), controller.getOne)
  // Update current user data
  .put(passport.authenticate('jwt', { session: false}), controller.update)
  // Delete current user
  .delete(passport.authenticate('jwt', { session: false}), controller.delete);

module.exports = router;

./API/пользователей/model.js

var mongoose = require('mongoose');
var bcrypt = require('bcrypt');

var UserSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true
  }
});

// ... for simplicity imagine methods here to
// - hash passwords on a pre save hook using bcrypt
// - compare passwords using bcrypt when logging in

module.exports = mongoose.model('User', UserSchema);

./апи/Todos/model.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var momentSchema = new Schema({
  title: {
    type: String
  },

  // Bunch of other fields here...

  _user: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  }
});

module.exports = mongoose.model('Moment', momentSchema);

Я пропустил часть кода примера, чтобы он был чистым и простым.

Например, контроллер Пользователь будет включать Модели и его функции:

  • controller.create - регистрация новых пользователей (возвращает токен)
  • controller.login - после комбинации имени пользователя и пароля, подтвержденной Passport Local, затем верните действительный токен
  • controller.getOne - на основе идентификатора пользователя, полученного из токена JWT, вернуть пользовательские данные из Mongo с помощью Mongoose.
  • controller.update - обновить данные пользователя в Mongo с помощью Mongoose
  • controller.delete. Удалить данные пользователя в Mongo с помощью Mongoose.

Контроллеры Todo будут делать что-то подобное - просто взаимодействуя с данными Mongo через Mongoose, но запросы всегда будут включать идентификатор пользователя, чтобы связать конкретный (например) элемент Todo с аутентифицированным пользователем (аутентифицированный через JWT).

Испытательная головоломка

Как я могу проверить что-то подобное с помощью комбинации Mocha, Chai и SuperTest?

Будет ли я:

  • создать тестовую базу данных в Mongo и иметь строку соединения в тестах иначе? Это означало бы сохранение фактических данных, хранящихся в базе данных для тестирования.
  • Как-то изморозить данные и вообще не использовать тестовую базу данных? Но тогда как пользователь может сохранить/войти в систему, чтобы получить токен?

Как тестирование будет выполняться локально при разработке по сравнению с развертыванием с использованием некоторого инструмента CI (чего я еще не получил в своих исследованиях)?

Любая помощь будет высоко оценена, и я надеюсь, что я дал достаточно информации с фиктивными данными/кодом выше:/

4b9b3361

Ответ 1

Во время тестирования вы обычно издеваетесь над своей mongo DB (что-то вроде mongo-mock). Таким образом, вам не нужна фактическая база данных, запускающая ваши тесты (вы не тестируете базу данных, а ваш код).

Во время тестирования вы замените mongodb на mongo-mock, а затем запустите свой тест. Чтобы получить свой токен, вам нужно будет отправить на свой /me URL-адрес с действительными издеваемыми учетными данными, эта конечная точка вернет токен, который затем будет использоваться при следующем вызове, чтобы проверить вашу другую конечную точку.

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

app.use(validate_jwt_middleware);
app.use('/users', userRouter);

Таким образом, если токен недействителен, он недействителен для всего сайта, а не только для вашего раздела.

Кроме того, я не использую SuperTest, но chai-http, поэтому я не могу помочь вам с вашей спецификой.

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