TL; DR - Qual è il modo di testare le risorse in un'API nodo (Express) che utilizza JWT per l'autenticazione solo con il token stesso concesso ad un login username/password?Come testare un'API di nodo che utilizza l'autenticazione JWT (con accesso utente per ottenere token)
Sono un po 'nuovo alla sperimentazione e volevo avere qualche consiglio. L'obiettivo finale è quello di avere un'API completamente testata e quindi iniziare a imparare come ottenere quello collegato a una soluzione di integrazione continua.
tecnologie in uso
- ho scritto un'API in Nodo utilizzando espresso.
- Mongo è il database.
- Mongoose viene utilizzato come ODM.
- jsonwebtoken il pacchetto viene utilizzato per creare/verificare token.
- Il passaporto viene utilizzato per aggiungere facilmente l'autenticazione utente come middleware Express sui percorsi.
API Informazioni
L'API ha varie risorse - le specifiche di cui non sono importanti a questa domanda, ma consente solo finta che sia l'applicazione Todo onnipresente per semplicità.
Ogni singola risorsa salvata nel database è associata a un singolo utente.
L'API utilizza JWT per l'autenticazione tra i diversi endpoint di risorse. Il token stesso contiene l'ID utente univoco che viene archiviato sulla risorsa in un database Mongo. Per ottenere il token stesso, l'utente deve prima registrarsi (che restituisce un token) e quindi accedere per ottenere un nuovo token.
Codice di pretesa.
ho intenzione di semplificare il codice qui sotto e non fare uso di qualsiasi file di configurazione dell'ambiente, ecc ...
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'));
});
./api/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/users/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's data
.get(passport.authenticate('jwt', { session: false}), controller.getOne)
// Update current user's data
.put(passport.authenticate('jwt', { session: false}), controller.update)
// Delete current user
.delete(passport.authenticate('jwt', { session: false}), controller.delete);
module.exports = router;
./api/users/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);
./api/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);
ho omesso parte del codice esempio per tenerlo pulito e semplice.
Per esempio, il controllore dell'utente di includerebbe le modelle e le sue funzioni sarebbero:
- controller.create - iscrizione per i nuovi utenti (rendimenti token)
- controller.login - dopo la combinazione nome utente/password confermata da Passport Local, quindi restituire un token valido
- controller.getOne - basato sull'uso r ID recuperato dal token JWT, restituisce i dati dell'utente da Mongo usando Mongoose.
- controller.update - Aggiornare i dati dell'Utente in Mongo utilizzando Mongoose
- controller.delete - Cancellare i dati dell'Utente in Mongo utilizzando Mongoose
controller Il del Todo sarebbe fare qualcosa di simile - basta interagire con i dati Mongo tramite Mongoose ma le query includeranno sempre l'ID utente per associare l'elemento Todo specifico (ad esempio) con l'utente autenticato (autenticato tramite JWT).
Testing Conundrum
Come potrei fare per testare qualcosa di simile utilizzando una combinazione di Mocha, Chai e Supertest?
Would I:
- creare un database di prova all'interno di Mongo e hanno la stringa di connessione essere diverso nelle prove? Ciò significherebbe il salvataggio dei dati effettivi memorizzati nel database per il test.
- Mock i dati in qualche modo e non utilizzare affatto un database di test? Ma allora come viene gestito il salvataggio/login dell'utente per recuperare il token?
In che modo i test possono funzionare localmente durante lo sviluppo rispetto a quando si esegue una distribuzione utilizzando uno strumento CI (qualcosa che devo ancora raggiungere nei miei studi)?
Tutta l'assistenza sarebbe molto apprezzato e spero che ho dato abbastanza informazioni con i dati/codice fittizio di cui sopra:./
Ciao! L'hai capito? Sto anche cercando di implementare questo tipo di test. –