- mocha: nos ayuda a correr los test
- supertest: levanta un servidor temporal
- sinon: crea mocks para tests
- proxyquire inyecta los mocks cuando se requieren los paquetes
Tu primera experiencia con Node.js
¿Dónde aprender backend con Node.js actualizado?
Todo lo que aprenderás sobre backend con Node.js
¿Qué es Node.js?
¿Qué es Node.js y para qué sirve?
Diferencias entre Node.js y JavaScript
Resumen: Diferencias Nodejs y Javascript
Instalación de Node.js
Arquitectura orientada a eventos
Node.js para la web
Manejo y uso de Streams con Node.js
Introducción a streams
Readable y Writable streams
Duplex y Transforms streams
Uso de utilidades de Node.js
Sistema operativo y sistema de archivos
Administrar directorios y archivos
Consola, utilidades y debugging
Clusters y procesos hijos
Crea tu primer proyecto en Express.js
¿Qué es Express.js y para qué sirve?
Creando tu primer servidor con Express.js
Request y Response Objects
Aprende a crear un API con REST
Anatomía de una API Restful
Estructura de una película con Moockaru
Implementando un CRUD en Express.js
Métodos idempotentes del CRUD
Implementando una capa de servicios
Cómo conectarse con librerías externas en Express.js
Creación de una BD en MongoAtlas
Conexión a MongoAtlas una instancia de MongoDB
Conexión con Robot3T y MongoDB Compass a una BD
Implementación de las acciones de MongoDB
Conexión de nuestros servicios con MongoDB
Conoce como funcionan los Middleware en Express.js
¿Qué es un middleware? Capa de manejo de errores usando un middleware
Manejo de errores asíncronos y síncronos en Express
Capa de validación de datos usando un middleware
¿Qué es Joi y Boom?
Implementando Boom
Implementando Joi
Probar la validación de nuestros endpoints
Middlewares populares en Express.js
Implementa tests en Node.js
Creación de tests para nuestros endpoints
Creación de tests para nuestros servicios
Creación de tests para nuestras utilidades
Agregando un comando para coverage
Debugging e inspect
Despliega tu primera aplicación en Express.js
Considerando las mejores prácticas para el despliegue
Variables de entorno, CORS y HTTPS
¿Cómo implementar una capa de manejo de caché?
¿Cómo contener tu aplicación en Docker?
Despliegue en Now
Conclusiones
¿Qué aprendiste en este curso?
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Aportes 55
Preguntas 19
La clase no estuvo muy clara. A mi parecer faltó explicar con más claridad lo relacionado con los test en javascript para poder entender más fácilmente lo que se estaba estudiando.
Este profesor sabe mucho del tema pero explica demasiado rápido y no se alcanza a entender muchas de las cosas que habla.
Investigué las documentaciones de las librerías para entender la clase y estos son mis apuntes por si les sirven.
⠀
⠀
<h1>Consideramos un testit(mensaje, function () {});
</h1>
⠀
Si dentro del callback se lanza un error, el test se da por fallido y se pasa al siguiente test.
En caso de que la ejecución del callback termine sin errores entonces se pasa al siguiente test automáticamente.
⠀
Si en la ejecución del callback llamamos a una función asíncrona, debemos pasarle una función ‘done’ como parámetro (el nombre es arbitrario).
⠀
Si pasamos ese parámetro mocha sabrá que debe esperar a que la ejecutemos para pasar al siguiente test y darlo como aprobado. O en caso de que ejecutemos done(error), sabrá que debe pasar al siguiente pero dándolo como fallido.
it(mensaje, function (done) {
setInmediate(() => done());
});
En caso de tengamos una promesa podemos simplemente retornarla y mocha esperará a que la promesa se complete, dando el test como aprobado o fallido dependiendo de si se resuelve correctamente o no.
⠀
Debemos utilizar el callback done o retornar una promesa, pero no utilizar ambos o se producirá un error.
it(mensaje, async function () {
return Promise.resolve('hola');
});
⠀
También podemos realizar un test asíncrono y tratarlo como síncrono con async/await. En este caso, al igual que en el caso síncrono, el test depende de si la función finaliza correctamente o finaliza con un error.
⠀⠀
it(mensaje, async function () {
const promesa = Promise.resolve('hola');
await promesa;
});
⠀
Como no envolvemos el await en un try/catch, este lanzará un error en caso de que la promesa sea rechazada, por lo tento el test pasará fallido.
⠀
⠀
Para esto utilizamos una librería llamada supertest, la cual sirve para testear servidores HTTP NODE.js, nos permite envíar solicitudes HTTP de tipo GET, POST, PATCH, PUT, y DELETE, y recibir la respuesta.
⠀
supertest nos provee una función a la que le debemos pasar nuestra app express como parámetro (con sus rutas establecidas), y nos retornará un objeto por el cual podemos relizar solicitudes y validaciones.
⠀
const createRequester = require('supertest');
const request = createRequester(app);
request
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
⠀
Si estamos en un test mocha, podemos pasar el done a la función end.
⠀
request
.get('/user')
.expect(200)
.end(done);
⠀
De esta manera, si hay un error mocha recibirá un done con el error y el test fallará, y si no hay error, no fallará porque done no recibirá un error. End recibe un error first callback.
⠀
Si no usamos la función end, los expect lanzarán errores en el segundo parámetro y podemos capturarlos de la siguiente manera…
⠀
request
.get('/user')
.expect(200, done);
⠀
Para leer la respuesta podemos usar un then
⠀
request
.get('/user')
.then(response => {
assert(response.body.email, '[email protected]');
});
Les recomiendo jest para los test unitarios, tanto en el front como en el back
Aprendí muy poco en esta clase.
.
Voy a leer los comentarios, y ver de nuevo la clase.
.
De aquí salgo aprendiendo-
.
VUAAAAAAAAAAMOS
Al ejecutar el script de test me dio un error porque faltaba setear la variable NODE_ENV
“test”: “set NODE_ENV=development && mocha --exit”
No olviden en test-server hacer uso del parse de express para formato json, el no hacerlo puede generarle error, en su defectoque la prueba falle.
const express = require('express')
const supertest = require('supertest')
function testServer(route){
const app = express()
app.use(express.json())
route(app)
return supertest(app)
}
module.exports = testServer
Algo que me di cuenta, es que es super importante que al hacer el deepEqual asegurarse que los datos que estan comparando sean exactamente iguales. En este caso tanto la data como el mensaje que se reciben.
Me estaba dando errores porque en el mensaje que retornaba de las rutas era diferente al que comparaba en el test. Me salía este error:
.
Así que hay que estar muy pendientes con este tipo de errores.
¿Alguien sabe por qué esto funciona
En ‘routes/movies.js’
const MovieService = require('../services/MovieService')
En ‘test/routes.movies.test.js’
const route = proxyquire('../routes/movies', {
'../services/MovieService': MoviesServiceMock
})
Pero esto no:
En ‘routes/movies.js’
const { MovieService } = require('../services/')
En ‘test/routes.movies.test.js’
const route = proxyquire('../routes/movies', {
'../services/': { MovieService: MoviesServiceMock }
})
?
Si alguno tuvo problemas con el deepEqual, es porque la función está deprecada, la correcta es :
assert.deepStrictEqual(res.body, {
data: moviesMock,
message: 'movies listed',
});
Repositorio de la clase:
https://github.com/glrodasz/platzi-backend-node/tree/creacion-de-tests-para-nuestros-endpoints
Las dependencias que instalaremos solo se usarán en modo de desarrollo cuales son
El objetivo de esto es probar unicamente las rutas, no nos conectaremos a nuestros servicios como mongoDB si no que lo haremos a nuestros Mocks
Crearemos el archivo donde haremos los test
Importamos las dependencias que nos ayudarán
const assert = require('assert');
const proxyquire = require('proxyquire');
Importamos el creador de sevidores temporales y los mocks
const { moviesMock, MoviesServiceMock } = require('../utils/mocks/movies.js');
const testServer = require('../utils/testServer');
Esta funcion reemplazará el requiere del servicio de mongo por el de Mock que importamos
describe('routes - movies', function() {
const route = proxyquire('../routes/movies', {
'../services/movies': MoviesServiceMock
});
// una vez realizado el cambio proxiquery nos
// nos devuelve el mismo archivo pero con las
// modificaciones, y esto lo podemos guardar
// en una variable
Una vez el mock inyectado se lo pasamos a supertes que hará un servidor temporal
const request = testServer(route);
Creamos una prueba pero en vez de inyectar algo hará un unit test, le pasamos el nombre del test y la función a ejecutar
El done quiere fucionaría como un next, es decir termina aquí
describe('GET /movies', function() {
it('should respond with status 200', function(done) {
request.get('/api/movies').expect(200, done);
});
it( una descripción de lo que deberia dar, funcion a ejecutar
it('should respond with status 200', function
…
La función no es mas que un servidor temporal con el archivo modificado, dentro de este haremos un
routes.get(ruta a probar, expect(status esperado, done))
request.get('/api/movies').expect(200, done);
Ahora usaremos el .end que recibe una función que tiene el resultado de la petición y si hay algun error,
.end((err, res) => {
assert.deepEqual(res.body, {
data: moviesMock,
message: 'movies listed'
});
usaremos assert.deepEqual(valor 1, valor 2)
cual comparará los datos
instalar: npm i -D mocha supertest sinon proxyquire
Tal y como todo proxy sirve para interceptar procesos, proxyquire sirve para interceptar un módulo (require).
const route = proxyquire('../routes/movies', {
'../services/movies': MoviesServiceMock,
});
El primer parámetro representa la ruta del archivo donde pensamos interceptar el módulo (require) Ej.: ‘…/routes/movies’.
El segundo parámetro son pares “llave-valor” en los cuales, respectivamente, cada llave representa el módulo que se quiere interceptar (Ej.: ‘…/services/movies’), y cada valor representa el módulo (Ej.: MoviesServiceMock) por el cual se va a reemplazar el (módulo de la llave) que se está interceptando.
Utilizando lo que tenemos hasta ahora quedaría algo como esto:
const route = proxyquire('../routes/movies', {
'../services/movies': require('../utils/mocks/movies').MoviesServiceMock,
});
o más a fondo:
// en el archivo routes/movies.js quedaría algo así
const MoviesService = require('../services/movies');
const { MoviesServiceMock } = require('../services/mocks/movies')
const MoviesService = MoviesServiceMock;
// o sea sobrescribiendo el contenido del primer "MoviesService"
Espero no haber confundido más a nadie 🤣
creo que falta mas detalles sobre el tema de test, debería ser un modulo completo.
Si modificaron alguna parte del código con anterioridad y ahora tienen problemas con MOCHA, este código les puede ayudar.
require('dotenv').config();
const config = {
dev: (process.env.NODE_ENV || '').trim() !== 'production',
port: process.env.PORT || 3000,
cors: process.env.CORS,
dbUser: process.env.DB_USER,
dbPass: process.env.DB_PASSWORD,
dbHost: process.env.DB_HOST,
dbName: process.env.DB_NAME,
};
module.exports = {
config,
};
he encontrado esta informacion acerca de los
tes
ya que mas adelante podrias no entender nada.
Y si encuentras mi comentario en el siguiente video, me das un corazonsito ❤️
Siempre es bueno escribir las cosas un@ mism@… pero a veces es más fácil con un simple copy/paste:
npm i -D mocha supertest sinon proxyquire
😃
cuando vayan a crear los ‘servicios’ de mock, asegúrense que las funciones tenga el mismo nombre que del servicio original (osea, si en su capa de servicio para obtener peliculas es getAll, en el mock coloquenlo igual), dure media hora con un error por culpa de una ‘s’ 😃
y realmente la consola no es que ayudo mucho para solucionar el error, ya que me daba a entender que el error estaba en el archivo de test en si, y no en el mock xd
Me da el siguiente error ! 😢😢😭😭

TypeError: route is not a function
Si por alguna razón estás usando Typescript en lugar de javascript como yo, este comando te resumirá horas de búsqueda 😅
"scripts": {
"test": "mocha -r ts-node/register 'tests/**/*.ts'"
},
Ayuda!!! Por fa!
Hola a todos, he intentado corregir los test para que me funcionen y no me ha sido posible:
Siendo el script de test:
“test”: “SET NODE_ENV=development& mocha --exit”
Esto me sale en consola:
$ npm run test
[email protected] test D:\platzi-backend-node-implementando-una-capa-de-servicios\movies-api
SET NODE_ENV=development& mocha --exit
Error: No test files found: "test"
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] test: SET NODE_ENV=development& mocha --exit
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Daniel\AppData\Roaming\npm-cache_logs\2020-07-15T14_43_35_626Z-debug.log
Realmente no veo nada adicional en el log que refiere el error del arranque.
alguien de dio este error.
npm i -D mocha supertest sinon proxyquire
Con mocha 9 se obtiene el error
Error: Not supported
at formattedImport
Para solucionar el problema de manera temporal se debe de utilizar la versión mas antigua, ejemplo “mocha”: “^6.1.4”, con eso, el se puede continuar con la clase.
✌
todo un gigachad hecho y derecho!
El test nos sirve para ver la calidad y futuro de nuestra app.
npm i -D mocha supertest sinon proxyquire
No entendi como se relacionan las rutas de MoviesServiceMock, cuando hacemos el test con describe, por ejemplo para seleccionar la ruta con getMovie pasando un ID
El test me ayudó a descubrir que mi message decia ‘movie listed’ en vez de ‘movies listed’, un error simple que tal vez nunca me hubiera dado cuenta sin el test. Súper cool la herramienta
npm i -D mocha supertest sinon proxyquire
El video esta incompleto, hay archivos que Guillermo no explica como por ejemplo utils/mocks/mongoLib.js y otros dos archivos que estan en la carpeta de test, tampoco explica el buildMessage.js en la carpeta de utils.
Clase muy incompleta -.-
Los test no tienen en cuenta el validationSchema que hace parte de la ruta.
Excelente, no tenía en mente la importancia de los test de prueba y como muchos siempre los omito, pero creo que de hoy en adelante será necesario realizarlos en mi código.
proxiquire
Instalando dependencias
Creando test server para pruebas
Creando test server para pruebas
Compañeros ayuda!! … Me arroja “Type: request.get is not a function” del routes.movies.test.js… Pero parece que soy el único 😦
Creo que no fue muy clara la clase, me costó bastante seguirle el hilo. Aun así logré completarla y entender que los test son importantes pero me gustaría que hubiera sido mejor explicada.
A mi me daba error porque en el config/index.js en la constante config había añadido un .trim() al final de NODE_ENV para solucionar un problema de una clase.
Quité este .trim() y anduvo bien, pero no creo que sea una solución completa.
Si a alguien le pasó lo mismo, lo invito a compartir su solucion!
Así estaba mi codigo:
const config = {
dev: process.env.NODE_ENV.trim() !== 'production',
port: process.env.PORT || 3000,
// etc
}
Me daba el siguiente TypeError:
TypeError: Cannot read property 'trim' of undefined
at Object.<anonymous> (F:\Atom\Platzi\BackendNodeJS\moviesAPI\config\index.js:4:31)
Sacando el .trim() queda así:
const config = {
dev: process.env.NODE_ENV !== 'production',
port: process.env.PORT || 3000,
// etc
}
Y pasa efectivamente los test. De nuevo, si alguien tiene una mejor solución, lo invito a compartirla!
Buenas.
Alguien ha logrado hacer los test para el post, put y delete.
Me encuentro con el problema de que si intento hacer un post, el createMovie, le da igual el contenido aunque este el validator en medio, puedo hacer un post sin enviar nada, y me devuelve un 200, puedo romper cualqueir cosa que el 200 vuelve =(
Los test nos garantizan tener un código de buena calidad y si en el futuro hay cambios no se va a romper nuestro código.
Hola a todos, tengo una pregunta que quisiera pudieran aclararme, ¿Cuál es el sentido de hacer pruebas con mocks? al ver la este video pienso que no se esta llegando al endpoint a realizar al request, si no estamos haciendo el mockup, entonces ya se que voy a resolver, y si alguien cambia la funcionalidad del endpoint, la prueba seguiría pasando probablemente porque no modificaran el mock, creo que estoy confundido, pueden ayudarme a salir de esta duda?
Este fue mi error…
const assert = require('assert').strict;
it('Should respond with the list of movies', function (done) {
request.get('/api/movies').end((err, res) => {
assert.deepStrictEqual(res.body, {
data: moviesMock,
message: 'movies listed',
});
done();
});
});
mocha: nos ayuda a correr los test
supertest: levanta un servidor temporal
sinon: crea mocks para tests
proxyquire inyecta los mocks cuando se requieren los paquetes
🌸🌟🌞
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Los Test****: Son una buena manera de poder asegurarse que nuestro codigo tiene calidad y que si en el futuro hay cambios no se vaya a romper nuestro codigo.
Hola les traigo lo que dijo el profe pero escrito
/** Verifica que tanto se parecen dos datos */
const assert = require('assert')
/** Cada require elegimos si obtenemos el paquete real o los mocks */
const proxyquire = require('proxyquire')
/** Mocks de la base de datos y los servicios */
const {
moviesMock,
MoviesServiceMock
} = require('../utils/mocks/movies')
/** Servidor de tests */
const testServer = require('../utils/testServer')
/** describe imprime en consola y corre la funcion siguiente*/
describe('route - movies', function() {
/**
* proxyquire toma el archivo del checkpoint 'routes/movies.js'
* para probar que las peticiones esten funcionando correctamente.
* Y para verificar que la respuesta es retornada de la manera que queremos
* se implantan el MovieServiceMock en el lugar donde se requiere la ruta de los servicios
*/
const route = proxyquire('../routes/movies', {
/** intercambia services/movies por la clase MoviesServiceMock */
'../services/movies': MoviesServiceMock
})
/** Crea un servidor de prueba que maneje esta ruta declarada */
const request = testServer(route)
/** describe imprime en consola y llama al callback */
describe('GET /movies', function() {
/**
* Prueba: imprime este mensaje y corre el callback
* request corre el servidor de pruebas generando una peticion get
* que va a la ruta expuesta, y el metodo expect
* declara esperar un status 200 y mediante done terminamos la prueba
*/
it('should respond with status 2000', function(done) {
request.get('/api/movies').expect(200, done)
})
/**
* Prueba: hace una peticion get a la ruta y verifica el contenido
* request.get accede a la ruta, .end maneja la respuesta y el error
* pero solamente vamos a evaluar la respuesta,
* asset es un modulo core de node que nos permite evaluar el tipo y contenido de valores y variables
* en este caso verificamos res.body sea estrictamente igual a lo que enviamos como segundo parametro
* y finaliza la prueba con done
*/
it('should respond with the list of movies', function(done) {
request.get('/api/movies').end((err, res) => {
assert.deepEqual(res.body, {
data: moviesMock,
message: 'movies listed'
})
done()
})
})
})
})
si proxyquire retorna un objeto, se tiene un error de tipo
TypeError: route is not a function
por lo que me toco sacar la funcion que espera testServer de esta forma, no creo sea la mejor pero me sirvió
const {moviesApi: route} = proxyquire('../routes/movies.js', {
'../services/movies': MoviesServiceMock
});
espero les sirva
El término ‘mocha’ no se reconoce como nombre de un cmdlet, función, archivo de script o programa ejecutable.
Alguien le ha salido ese error? he comprobado que si tengo instalado el mocha y tmb lo tengo en el package.json
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?