Let's test!!!
Typescript + Test + 驴GraphQL?
驴Qui茅n soy?
- Full Stack Developer en Lean Mind
- Apasionado del desarrollo
- Typescript lover 馃挋
Adri谩n Ferrera Gonz谩lez
@afergon
adrian-afergon
驴De qu茅 vamos a hablar?
Como testear una aplicaci贸n de manera simple
驴Por qu茅 hacer tests?
No tengo test
驴Por d贸nde empiezo?
- E2E
- Unitarios
- Integraci贸n
Si es un nuevo elemento
Si ya los elementos est谩n preparados
Si no conozco nada
E2E
- Son caros respecto a tiempo
- Cubren los casos de uso de forma humana
- Se necesita un entorno real
Caracter铆sticas
驴C贸mo?
- Docker
- Servicio desplegada
- Puppeteer
- Jest
E2E
import puppeteer from 'puppeteer';
describe('Display video', () => {
let browser: puppeteer.Browser;
let page: puppeteer.Page;
beforeEach(async () => {
browser = await puppeteer.launch({
headless: false,
});
page = await browser.newPage();
await page.emulate({
viewport: {
width: 500,
height: 2400,
},
userAgent: '',
});
await page.goto('http://localhost:3000/best-builds');
});
afterEach(async () => {
await browser.close();
});
it('should select a video and view details ', async () => {
await page.waitForSelector('[data-testid="video-item-1"]');
const button = await page.$('[data-testid="video-item-1"]');
if (button) {
await button.evaluate((element: Element) => element.click());
}
const html = await page.$eval('[data-testid="video-details-title-1"]', (e: any) => e.innerHTML);
expect(html).toBe('La amiga imaginaria y otros relatos de terror');
});
});
E2E
- Enterarnos si rompemos la aplicaci贸n
- Tener un andamio para mover la estructura a una que se pueda probar
- Garantizar que los casos de uso pedidos se cumplen
La finalidad
Unitarios
- Son r谩pidos de ejecutar y desarrollar
- Cubren abstracciones de c贸digo
- Deber铆an de probarse de forma aislada
Caracter铆sticas
驴C贸mo?
- Jest
Unitarios
// Test
describe('Videos', () => {
it('should return the specified number of videos', async () => {
const expectedQuantity = 4;
const videosRepository: VideosRepository = new VideosRepository();
const foundVideos: Video[] = await videosRepository.getVideos(expectedQuantity);
expect(foundVideos.length).toBe(expectedQuantity);
});
});
// Component
export VideosRepository {
// ...
public getVideos(quantity: number): Promise<Video[]> {
return Promise.resolve(videos.slice(0, quantity));
}
}
Integraci贸n
- Son r谩pidos de ejecutar y desarrollar
- Cubren un conjunto de funcionalidades
- Hay que falsear llamadas (mocks)
Caracter铆sticas
驴C贸mo?
- Jest
- Arquitectura
Integraci贸n
隆驴Arquitectura?!
Integraci贸n
Arquitectura
Acceso a datos
C谩lculos y operaciones
Representaci贸n
Repository
Service
View
mapper
mapper
Integraci贸n
Arquitectura
Repository
Service
View
1. Vamos a consumir los datos del servicio
Por lo que omitiremos la capa de presentaci贸n
Integraci贸n
Arquitectura
Repository
Service
1. Vamos a consumir los datos del servicio
describe('Videos service', () => {
it('should retrive the requested videos', async () => {
const allVideos = [ /* ? */ ];
const videoService = new VideoService();
const foundVideos = await videoService.find();
expect(foundVideos).toBe(allVideos);
});
});
2. Identificamos las dependencias y las inyectamos
describe('Videos service', () => {
it('should retrive the requested videos', async () => {
const allVideos = [ terrorVideo, actionVideo ];
const videoRepository = new VideoRepository();
const videoService = new VideoService(videoRepository);
const foundVideos = await videoService.find();
expect(foundVideos).toBe(allVideos);
});
});
Repository
Service
Integraci贸n
Arquitectura
3. Reemplazamos la llamada real por una propia
describe('Videos service', () => {
it('should retrive the requested videos', async () => {
const allVideos = [ terrorVideo, actionVideo ];
const videoRepository = new VideoRepository();
videoRepository.getVideos = jest.fn( () => Promise.resolve(allVideos) );
const videoService = new VideoService(videoRepository);
const foundVideos = await videoService.find();
expect(foundVideos).toBe(allVideos);
});
});
Repository
Service
Integraci贸n
Arquitectura
export class VideoService {
constructor() {
this.videoRepository = new VideoRepository();
}
public async find(): Video[] {
return videoRepository.getVideos();
}
}
驴Entonces tengo que cambiar todas las llamadas?
Repository
Service
Integraci贸n
Arquitectura
export class VideoService {
constructor(
private videoRepository = new VideoRepository()
) {}
public async find(): Video[] {
return videoRepository.getVideos();
}
}
No, solo le daremos un valor por defecto
Arquitectura
Repository
Service
Integraci贸n
Integraci贸n
Ventajas
- Probamos gran parte de nuestro c贸digo
- Invertimos poco tiempo en su desarrollo
- Su ejecuci贸n es ligera
Desventajas
- Hemos dejado reflejada informaci贸n en el test
- Estos test requieren mantenimiento.
- No son completamente reales
驴Qu茅 testear?
- Tipos simples
- Librer铆as de terceros
- Tipos complejos
- Mappers
Si
No
Questions?
Thank you!!
Let's test!!!
By afergon
Let's test!!!
This is a simple presentation about how we can test our typescript application
- 345