Consigue automatizar con Unit Testing y ser más productivo
El testing es una parte esencial en un producto de software. Nosotros como usuarios hacemos las pruebas necesarias en dispositivos. Pero esta tarea a la hora de desarrollar se vuelve tediosa y repetitiva, mucho mas cuando la aplicación que estamos haciendo es grande.
Te presento el unit testing en Flutter.
Las pruebas unitarias vienen a solucionar eso! La prueba de fondo la hace una persona encargada de QA nosotros igual podemos hacer las pruebas antes de entregar un producto.
“Es código que prueba una porción de código”
Podemos ver esto en distintas tecnologías. Frameworks. todo esto esta relacionado con la creación de software y su funcionamiento correcto.
¿Que viene a solucionar el unit testing?
El beneficio es la optimización de procesos ya que podemos hacer que esto se ejecute automáticamente cada vez que hacemos un cambio.
Se te puede presentar que esto llegue a solicitarte que sepas más de un concepto con antelación. El unit testing implica también que sepamos de generación de código y/o de “mockeo” de entidades. Esto cuando hacemos testing de un servicio, puede ser una API REST.
Solo solamente el unit testing, sino la automatización de cualquier proceso para mejorar la calidad mejorar enormemente tu productividad como desarrollador.
Estructura Inicial
Se compone de una función test() que contiene 2 parámetros.
1. Descripción.
La recomendación de expertos nos dice que esta debe ser escrita de forma en la que “obtengamos x cuando hacemos y”, entonces:
“Should have [this] when [i do this].“
Ejemplo:
“Debería obtener un numero positivo cuando ejecuto add()”
2. Función Callback.
Una función callback en la programación es una función que se ejecutara en algún punto dentro de una función. Este concepto en test() se aplica con la siguiente estructura.
Ejemplo:
// test/main_test.dart
void main {
test('descripcion cualquiera', () {
// Arrange: es como crear un miniambiente para correr el test
// Act: Aqui es donde haces correr toda la lógica
// Assert: se verifican resultados con la funcion expect()
});
}
Okey hagamos un parentesis en expect().
Este que recibe 2 parámetros:
- actual: el valor que tengo
- matcher: clase que nos ayuda verificar algo.
- matcher puede ser un numero: isEmpty, isFalse, isNegative,[0..9]
Acá te dejo la documentación para ver los matchers, es un concepto corto, y rápido de entender:
https://api.flutter.dev/flutter/package-matcher_matcher/package-matcher_matcher-library.html
Veamos la práctica con un ejemplo
Aca hacemos el test de un servicio cualquiera del consumo de una API REST(Post) y verificamos si la data esta llegando correctamente.
lib/animals_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
class AnimalsService {
final String _baseUrl = 'https://api.animalitos.com';
Future<List<Map<String, dynamic>>> getAnimals() async {
final response = await http.post(
Uri.parse('$_baseUrl/animals'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'filter': 'all'}),
);
if (response.statusCode == 200) {
final List<dynamic> data = jsonDecode(response.body);
return data.cast<Map<String, dynamic>>();
} else {
throw Exception('Error al obtener animales');
}
}
}
test/animals_service_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:http/http.dart' as http;
import 'package:tu_proyecto/animals_service.dart'; // Ajusta la ruta
class MockHttpClient extends Mock implements http.Client {}
void main {
// Llamado de mocks
late AnimalsService animalsService;
late MockHttpClient mockHttpClient;
setUp(() {
// Inyectamos el mock
mockHttpClient = MockHttpClient();
animalsService = AnimalsService();
});
test('getAnimals retorna una lista de animales cuando la respuesta es 200', () async {
// arrange
when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body')))
.thenAnswer((_) async => http.Response(jsonEncode([{'name': 'Perro'}, {'name': 'Gato'}]), 200));
// act
final animals = await animalsService.getAnimals();
// assert
expect(animals, isA<List<Map<String, dynamic>>>());
expect(animals.length, 2);
expect(animals[0]['name'], 'Perro');
});
// arrange
when(
() => mockHttpClient.post(
any(),
headers: any(named: 'headers'),
body: any(named: 'body')
)
).thenAnswer((_) async => http.Response('Error', 500));
// act and assert
expect(() => animalsService.getAnimals(), throwsException);
}
PD: Si viste en el ejemplo se incorpora una nueva función para el callback llamada when().
when:
Es para definir el comportamiento de un método y una analogía seria si una manzana siempre es roja, entonces cuando alguien pregunte por el color de la manzana, la respuesta será roja.
Hablemos de aspectos extras:
Sabemos que tenemos que hacer testing de procesos como la obtención de datos de una API rest, o simplemente obtención de datos de un servicio de terceros.
Para esto podemos utilizar herramientas como:
- mockito
- mocktail.
Y hacemos lo siguiente para hacer su prueba.
Además se utiliza algo llamado coverage para contabilizar el porcentaje de lineas que se han testado en la app.
Para este último existe un package llamado “coverage”.
Por ultimo ejecutamos test
Ejecutamos el test con el siguiente comando.
// default: main_test.dart
flutter test
// Si tienes algun archivo en particular
flutter test [nombre_del_archivo.dart]
y YA!
Otros artículos para esta serie
1 — Unit testing
2 — Widget Testing
3 — Integration Testing(Pronto)
4 — Gold Testing(Pronto)
Tu contribución.
👏 ¡Presiona el botón de aplaudir a continuación para mostrar tu apoyo y motivarme a escribir mejor!
💬 Deje una respuesta a este artículo brindando sus ideas, comentarios o deseos para la serie.
📢 Comparte este artículo con tus amigos y colegas en las redes sociales.
➕ Sígueme en Medium.
⭐ Ve los ejemplos prácticos desde mi canal en Youtube: Pacha Code