Mocha — это фреймворк для тестирования JavaScript, который предоставляет гибкую структуру для написания и организации тестов. Для тестирования веб-приложений, работающих с роутингом, Mocha становится незаменимым инструментом. Это тестирование помогает убедиться, что маршруты и обработчики запросов работают правильно и возвращают ожидаемые результаты.
Роутинг — это процесс, который управляет тем, как запросы от клиента направляются к соответствующим обработчикам серверных маршрутов. В веб-разработке роутинг обычно ассоциируется с такими библиотеками, как Express.js, которые позволяют задавать различные пути и обрабатывать соответствующие запросы.
Прежде чем приступить к тестированию роутинга, важно понимать следующие компоненты:
GET, POST, PUT,
DELETE, каждый из которых имеет разные особенности в
контексте роутинга.Для тестирования роутинга часто используется связка Mocha с дополнительными инструментами, такими как Chai и Supertest. Mocha обеспечит запуск тестов и структуру, Chai — ассерты, а Supertest — возможность отправки HTTP-запросов к серверу и проверки результатов.
Пример установки зависимостей:
npm install mocha chai supertest --save-dev
Затем необходимо создать сервер, который будет обслуживать маршруты, которые мы будем тестировать. В данном случае используется Express.js.
const express = require('express');
const app = express();
app.get('/home', (req, res) => {
res.status(200).send('Welcome to the homepage');
});
module.exports = app;
Теперь, когда сервер готов, можно приступать к тестированию.
Один из самых популярных типов запросов — это GET,
который используется для получения данных с сервера. Для тестирования
таких запросов с использованием Mocha, Chai и Supertest можно написать
следующие тесты.
Пример теста для маршрута /home:
const request = require('supertest');
const app = require('./app');
const { expect } = require('chai');
describe('GET /home', function() {
it('должен возвращать статус 200 и сообщение "Welcome to the homepage"', function(done) {
request(app)
.get('/home')
.expect(200)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.equal('Welcome to the homepage');
done();
});
});
});
В этом тесте используется метод
request(app).get('/home'), который имитирует отправку
GET-запроса на сервер. В методе expect(200) проверяется,
что сервер вернул статус 200. Затем с помощью Chai делаем проверку тела
ответа, ожидая строку “Welcome to the homepage”.
POST-запросы используются для отправки данных на сервер. Чаще всего они применяются для создания новых записей или выполнения операций, требующих данных от клиента. Пример теста для POST-запроса:
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username === 'admin' && password === 'password') {
return res.status(200).send('Login successful');
}
return res.status(401).send('Invalid credentials');
});
describe('POST /login', function() {
it('должен возвращать статус 200 при правильных учетных данных', function(done) {
request(app)
.post('/login')
.send({ username: 'admin', password: 'password' })
.expect(200)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.equal('Login successful');
done();
});
});
it('должен возвращать статус 401 при неверных учетных данных', function(done) {
request(app)
.post('/login')
.send({ username: 'admin', password: 'wrongpassword' })
.expect(401)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.equal('Invalid credentials');
done();
});
});
});
Здесь мы проверяем два сценария: успешный логин с правильными данными
и отказ в случае неверных данных. В обоих тестах используется метод
send() для отправки данных в теле запроса.
Маршруты могут принимать параметры через URL. Например, маршрут для получения информации о пользователе по его идентификатору может выглядеть так:
app.get('/user/:id', (req, res) => {
const { id } = req.params;
res.status(200).send(`User ID is ${id}`);
});
Для тестирования таких маршрутов необходимо передать параметр в URL:
describe('GET /user/:id', function() {
it('должен возвращать правильный ID пользователя', function(done) {
request(app)
.get('/user/123')
.expect(200)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.equal('User ID is 123');
done();
});
});
});
В этом тесте проверяется, что в ответе содержится строка с правильным ID пользователя.
Очень важно тестировать ошибки, которые могут возникнуть при обработке запросов. Например, если маршрут не существует, сервер должен вернуть ошибку 404:
app.use((req, res) => {
res.status(404).send('Not Found');
});
describe('404 ошибка', function() {
it('должен возвращать статус 404 для несуществующего маршрута', function(done) {
request(app)
.get('/non-existent-route')
.expect(404)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.equal('Not Found');
done();
});
});
});
Здесь проверяется, что сервер корректно обрабатывает запросы к несуществующим маршрутам и возвращает статус 404 с соответствующим сообщением.
Часто при тестировании роутинга необходимо работать с асинхронными
операциями, например, с запросами к базе данных. Mocha предоставляет
поддержку асинхронных тестов через использование функции
done() или возврат промисов.
Пример асинхронного теста с промисами:
app.get('/data', (req, res) => {
return new Promise((resolve) => {
setTimeout(() => {
res.status(200).send('Async data');
resolve();
}, 1000);
});
});
describe('GET /data', function() {
it('должен возвращать данные асинхронно', function() {
return request(app)
.get('/data')
.expect(200)
.then((res) => {
expect(res.text).to.equal('Async data');
});
});
});
Здесь используется промис для симуляции асинхронной операции. Mocha ожидает завершения промиса, прежде чем продолжить выполнение теста.
Роутинг часто включает использование промежуточных обработчиков (middleware). Они могут быть использованы для аутентификации, логирования и других целей. Тестирование таких маршрутов требует проверки работы middleware.
Пример теста для маршрута с middleware:
const checkAuth = (req, res, next) => {
if (req.headers.authorization === 'Bearer validtoken') {
next();
} else {
res.status(401).send('Unauthorized');
}
};
app.get('/protected', checkAuth, (req, res) => {
res.status(200).send('Protected data');
});
describe('GET /protected', function() {
it('должен возвращать статус 200 с правильным токеном', function(done) {
request(app)
.get('/protected')
.set('Authorization', 'Bearer validtoken')
.expect(200)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.equal('Protected data');
done();
});
});
it('должен возвращать статус 401 без токена', function(done) {
request(app)
.get('/protected')
.expect(401)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.equal('Unauthorized');
done();
});
});
});
Здесь проверяется, что middleware корректно защищает маршрут и отказывает в доступе без авторизации.
Тестирование роутинга с использованием Mocha позволяет убедиться