2016-05-17 23 views
12

TL; DR - Jaki jest sposób testowania zasobów w węźle API (Express), który używa JWT do uwierzytelniania tylko z tokenem przyznano login/hasło logowania?Jak przetestować interfejs API węzła, który korzysta z uwierzytelniania JWT (z logowaniem użytkownika, aby uzyskać token)?

Jestem trochę nowy w testowaniu i chciałem uzyskać porady. Ostatecznym celem jest przetestowanie w pełni przetestowanego API, a następnie rozpoczęcie nauki tego, jak podłączyć go do rozwiązania Continuous Integration.

Technologie stosowane

  • Pisałem API w Węzła wykorzystaniem Express,.
  • Mongo to baza danych.
  • Mongoose służy jako ODM.
  • Pakiet jsonwebtoken służy do tworzenia/weryfikacji tokenów.
  • Paszport służy do łatwego dodawania uwierzytelniania użytkownika jako oprogramowania pośredniego Express na trasach.

API Informacja

API ma różne zasoby - specyfika, które nie są istotne dla tego zapytania, ale pozwala tylko udawać, że to wszechobecne aplikacji Todo dla uproszczenia.

Każdy pojedynczy zasób zapisany w bazie danych jest powiązany z pojedynczym użytkownikiem.

Interfejs API wykorzystuje narzędzie JWT do uwierzytelniania na różnych punktach końcowych zasobów. Sam token zawiera unikalny identyfikator użytkownika, który jest przechowywany w zasobach w bazie danych Mongo. Aby uzyskać sam token, należy najpierw zarejestrować użytkownika (który zwraca token), a następnie zalogować się, aby uzyskać nowy token.

Przepisz kod.

mam zamiar uprościć poniższy kod i nie wykorzystuje żadnych configs namiotowe, itp ...

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); 

mam pominięto niektóre przykładowy kod, aby utrzymać go w czystości i proste.

Na przykład użytkownika kontroler będzie zawierać modele i jego funkcje będzie:

  • controller.create - zarejestruj dla nowych użytkowników (powraca tokena)
  • controller.login - po potwierdzeniu przez nazwę użytkownika/hasło przez lokalny paszport zwrotny ważny token
  • controller.getOne - w oparciu o wykorzystanie r ID pobrane z tokena JWT, zwróć dane użytkownika z Mongo za pomocą Mongoose.
  • controller.update - Aktualizacja danych użytkownika w Mongo pomocą Mongoose
  • controller.delete - Usuwanie danych użytkownika w Mongo użyciu Mongoose

kontrolerów Todo byłby zrobić coś podobnego - po prostu wchodząc w interakcje z danymi Mongo za pośrednictwem Mongoose, ale zapytania zawsze będą zawierać identyfikator użytkownika, aby powiązać określoną (na przykład) pozycję Todo z uwierzytelnionym użytkownikiem (uwierzytelnionym za pośrednictwem JWT).

Testowanie Conundrum

Jak bym go o coś takiego badania za pomocą kombinacji Mocha, Chai i SuperTest?

Would I:

  • stworzyć bazę testową w Mongo i mieć ciąg połączenia się różnić w testach? Oznaczałoby to zapisanie rzeczywistych danych przechowywanych w bazie danych do testowania.
  • Jakoś przetworzyć dane i nie używać w ogóle testowej bazy danych? Ale w jaki sposób jest zapisywane logowanie użytkownika/logowanie w celu odzyskania tokena?

W jaki sposób testy będą działać lokalnie podczas opracowywania w porównaniu do tego, kiedy wykonasz wdrożenie za pomocą jakiegoś narzędzia CI (coś, czego jeszcze nie zdążyłem się nawet nauczyć)?

Każda pomoc będzie mile widziane i mam nadzieję, że dałem wystarczająco dużo informacji z manekina danych/kodu powyżej.:/

+0

Witam! Wymyśliłeś to? Próbuję też wdrożyć tego rodzaju testy. –

Odpowiedz

1

podczas testów, ty normalnie drwić swoją Mongo DB (coś jak mongo-mock ten sposób, nie potrzebujesz rzeczywistej bazy danych do uruchomienia twoich testów (nie testujesz bazy danych, ale twój kod)

Podczas testów wymienisz mongodb na mongo-mock, a następnie wykonasz test. musisz umieścić na swoim URL-u o numerze /me z prawidłowymi fałszywymi danymi uwierzytelniającymi, ten punkt końcowy zwróci token, który następnie wykorzystasz przy następnym połączeniu przetestować twój drugi punkt końcowy.

Po stronie tokenów zazwyczaj sprawdzam to na początku żądania przed wprowadzeniem do innych punktów końcowych.(I nie był używany paszport ale idea jest):

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

ten sposób, jeśli token jest nieprawidłowy, to nieważne dla całej strony, nie tylko swoją sekcję.

Ponadto, nie używam SuperTestu, ale chai-http, więc nie mogę ci pomóc z twoją specyfiką.

Mam nadzieję, że to pomoże,