Entornos de desarrollo

1º DAM/DAW - Curso 2024-2025

User Tools

Site Tools


apuntes:testing

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
apuntes:testing [2025/03/23 17:38] – [Test de integración] Santiago Faciapuntes:testing [2025/03/30 19:55] (current) Santiago Faci
Line 7: Line 7:
  
 ===== Test unitarios ===== ===== Test unitarios =====
 +
 +==== Clases de utilidad ====
  
 <code javascript> <code javascript>
Line 41: Line 43:
         days = getDays(new Date('2024-01-01'), new Date('2024-01-01'));         days = getDays(new Date('2024-01-01'), new Date('2024-01-01'));
         expect(days).equal(0);         expect(days).equal(0);
 +    });
 +});
 +</code>
 +
 +==== Capa controller ====
 +
 +<code javascript>
 +const httpMocks = require('node-mocks-http');
 +const { describe, it, expect, afterEach } = require('@jest/globals');
 +
 +jest.mock('../../service/cities');
 +
 +const cityController = require('../../controller/cities');
 +
 +const cityService = require('../../service/cities');
 +const mockedFindCities = jest.spyOn(cityService, 'findCities');
 +const mockedRegisterCity = jest.spyOn(cityService, "registerCity");
 +const { mockCityArray, mockCityToPost, mockCityResponse, mockCityToRegister } = require('./mocks/cities');
 +
 +afterEach(() => {
 +    jest.clearAllMocks();
 +});
 +
 +describe('cities', () => {
 +    it('GET /cities should get a city list', async () => {
 +        const response = httpMocks.createResponse();
 +        const request = httpMocks.createRequest();
 +        request.app = {};
 +        request.app.conf = {};
 +        request.path = '/cities';
 +
 +        const mockedCityList = jest.fn(async () => {
 +            return mockCityArray;
 +        });
 +        mockedFindCities.mockImplementation(mockedCityList);
 +
 +        await cityController.getCities(request, response);
 +        expect(mockedFindCities).toHaveBeenCalledTimes(1);
 +        expect(response.statusCode).toEqual(200);
 +        expect(response._isEndCalled()).toBeTruthy();
 +        expect(response._getJSONData().length).toEqual(5);
 +    });
 +
 +    it('POST /cities should register a new city', async () => {
 +        const response = httpMocks.createResponse();
 +        const request = httpMocks.createRequest();
 +        request.app = {};
 +        request.app.conf = {};
 +        request.path = '/cities';
 +        request.body = mockCityToRegister;
 +
 +        const mockedRegisterCityResponse = jest.fn(async () => {
 +            return mockCityResponse;
 +        });
 +        mockedRegisterCity.mockImplementation(mockedRegisterCityResponse);
 +
 +        await cityController.postCity(request, response);
 +        expect(mockedRegisterCity).toHaveBeenCalledTimes(1);
 +        expect(response.statusCode).toEqual(201);
 +        expect(response._isEndCalled()).toBeTruthy();
 +        expect(response._getJSONData().id).toEqual(1);
 +        expect(response._getJSONData().name).toEqual('Zaragoza');
 +        expect(response._getJSONData().population).toEqual(700000);
 +        expect(response._getJSONData().altitude).toEqual(200);
 +        expect(response._getJSONData().age).toEqual(5);
 +        expect(response._getJSONData().area).toEqual(734734);
 +        expect(response._getJSONData().density).toEqual(2373);
 +        expect(response._getJSONData().foundationDate).toEqual('2020-12-01');
     });     });
 }); });
Line 59: Line 129:
 ===== Test de integración ===== ===== Test de integración =====
  
- Caso de uso: Ok (200 OK)+  * Caso de uso: **Ok (200 OK)**
  
 <code javascript> <code javascript>
Line 72: Line 142:
  
 describe('cities', () => { describe('cities', () => {
-    describe('GET /cities', () => { +  describe('GET /cities', () => { 
-        it('should get all cities', (done) => { +    it('should get all cities', (done) => { 
-            chai.request(app) +      chai.request(app) 
-                .get('/cities'+        .get('/cities'
-                .end((error, response) => { +        .end((error, response) => { 
-                    response.should.have.status(200); +           response.should.have.status(200); 
-                    response.body.should.be.a('array'); +           response.body.should.be.a('array'); 
-                    expect(response.body[0]).to.have.property('name'); +           expect(response.body[0]).to.have.property('name'); 
-                    expect(response.body[0]).to.have.property('altitude'); +           expect(response.body[0]).to.have.property('altitude'); 
-                    expect(response.body[0]).to.have.property('population'); +           expect(response.body[0]).to.have.property('population'); 
-                    expect(response.body[0]).to.have.property('foundationDate'); +           expect(response.body[0]).to.have.property('foundationDate'); 
-                    expect(response.body[0]).to.have.property('age'); +           expect(response.body[0]).to.have.property('age'); 
-                    expect(response.body[0]).to.have.property('area'); +           expect(response.body[0]).to.have.property('area'); 
-                    expect(response.body[0]).to.have.property('density');+           expect(response.body[0]).to.have.property('density');
  
-                    expect(response.body[0].name).to.equal('Zaragoza'); +           expect(response.body[0].name).to.equal('Zaragoza'); 
-                    expect(response.body[1].name).to.equal('Madrid'); +           expect(response.body[1].name).to.equal('Madrid'); 
-                    done(); +           done(); 
-                }); +         });
-        });+
     });     });
 +  });
 }); });
 </code> </code>
  
-Caso de uso: Registro (201 Created)+  * Caso de uso: **Registro (201 Created)**
  
 <code javascript> <code javascript>
Line 124: Line 194:
 </code> </code>
  
- Caso de uso: Validación (400 Bad Request)+  * Caso de uso: **Validación (400 Bad Request)**
  
 <code javascript> <code javascript>
Line 144: Line 214:
 }); });
 </code> </code>
 +
 +<code javascript>
 +. . .
 +"scripts": {
 +    "integration-test": "mocha src/test/integration --exit",
 +    . . .
 +. . .
 +</code>
 +
 +También podemos aprovechar para modificar el script ''test'' de forma que lance todos los tests: unitarios y de integración:
 +
 +<code javascript>
 +. . .
 +"scripts": {
 +    . . .
 +    "test": "npm run unit-test && npm run integration-test",
 +    . . . 
 +. . .
 +</code>
 +
 +Asi, podremos lanzar todos los tests solo con ''npm test''
 +
 +===== Crear un entorno de pruebas con Docker =====
 +
 +Colocaremos en la carpeta ''db'' del proyecto el script SQL que creará la base de datos y las tablas. También podemos añadir las sentencias ''INSERT'' que queramos para preparar datos según los casos de nuestros tests de integración.
 +
 +Podemos crear un fichero ''docker-compose.dev.yaml'' con la siguiente configuración:
 +
 +<code yaml>
 +version: "3.4"
 +name: cities
 +services:
 +  db:
 +    image: mariadb:11.3.2
 +    container_name: cities-db-dev
 +    environment:
 +      MYSQL_USER: 'user'
 +      MYSQL_PASSWORD: 'password'
 +      MYSQL_PORT: 3306,
 +      MYSQL_ROOT_PASSWORD: 'rootpassword'
 +    ports:
 +      - "3306:3306"
 +    volumes:
 +      - ./db:/docker-entrypoint-initdb.d
 +</code>
 +
 +Y podremos lanzar nuestro entorno de pruebas con el siguiente comando:
 +
 +<code bash>
 +santi@zenbook:$ docker compose -f docker.compose.dev.yaml up -d
 +</code>
 +
 +Para destruir el entorno:
 +
 +<code bash>
 +santi@zenbook:$ docker compose -f docker.compose.dev.yaml down
 +</code>
 +
 +También se puede simplemente detener:
 +<code bash>
 +santi@zenbook:$ docker compose -f docker.compose.dev.yaml stop
 +</code>
 +
 +O bien iniciar si está detenido:
 +
 +<code bash>
 +santi@zenbook:$ docker compose -f docker.compose.dev.yaml start
 +</code>
 +
 +====== Proyectos de ejemplo ======
 +
 +En [[https://github.com/codeandcoke/cities|cities]] puedes encontrar un proyecto con tests unitarios y de integración implementados. También está lo necesario para crear un entorno de pruebas y lanzar todos los tests utilizando dicho entorno.
  
 ---- ----
  
-(c) 2024 Santiago Faci+(c) 2025 Santiago Faci
apuntes/testing.1742751535.txt.gz · Last modified: 2025/03/23 17:38 by Santiago Faci