Primeros pasos con Dart y Flutter
Genera reportes HTML atractivos usando Allure Report y tus pruebas de Dart y Flutter.
INFO
Los paquetes principales para el usuario son allure_dart_test para suites de package:test y allure_flutter_test para pruebas de widgets de Flutter y suites de integration_test ejecutadas en el host. Si estás creando tu propia integración para un runner o framework personalizado, utiliza allure_dart_commons. Los tres paquetes se encuentran en el repositorio oficial allure-dart.
Configuración
1. Prepara tu proyecto
Asegúrate de tener instalada una versión reciente de la herramienta de Dart o Flutter.
Los paquetes oficiales de
allure-dartrequieren Dart 3.8 o superior. El adaptador de Flutter requiere además Flutter 3.24 o superior.Abre una terminal y ve al directorio del proyecto. Por ejemplo:
bashcd /home/user/myprojectInstala Allure Report siguiendo la guía de instalación.
Añade la integración como dependencia de desarrollo:
bashdart pub add --dev allure_dart_testbashflutter pub add --dev allure_flutter_testHabilita la integración en tus archivos de prueba. La forma más sencilla es el import drop-in: reemplaza el import del framework de pruebas por el import correspondiente de Allure y deja el resto del archivo igual.
Import original Import drop-in de Allure package:test/test.dartpackage:allure_dart_test/test.dartpackage:flutter_test/flutter_test.dartpackage:allure_flutter_test/flutter_test.dartpackage:integration_test/integration_test.dartpackage:allure_flutter_test/integration_test.dartLas librerías drop-in reexportan el framework original, así que
expect, los matchers y las demás APIs siguen funcionando. Añade un segundo import con alias para la API de runtime de Allure:dartimport 'package:allure_dart_test/test.dart'; import 'package:allure_dart_test/allure_dart_test.dart' as allure; void main() { group('authentication', () { test('login works', () async { await allure.feature('Authentication'); await allure.parameter('browser', 'chromium'); await allure.step('submit credentials', (step) async { await step.parameter('user', 'alice'); await allure.attachment( 'request', '{"user":"alice"}', contentType: 'application/json', fileExtension: 'json', ); }); expect(2 + 2, equals(4)); }); }); }dartimport 'package:allure_flutter_test/flutter_test.dart'; import 'package:allure_flutter_test/allure_flutter_test.dart' as allure; void main() { testWidgets('renders empty state', (tester) async { await allure.feature('Home screen'); await allure.step('pump widget', (_) async { await tester.pumpWidget(const MyApp()); }); expect(find.text('No items'), findsOneWidget); }); }dartimport 'package:allure_flutter_test/integration_test.dart'; import 'package:allure_flutter_test/allure_flutter_test.dart' as allure; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('signs in', (tester) async { await allure.story('Sign in'); expect(find.text('Sign in'), findsOneWidget); }); }Alternativamente, si prefieres mantener los imports originales del framework, instala el plugin de runtime una vez con
installAllure(). En pruebas de Dart, llámalo al inicio demain(); en pruebas de Flutter, llámalo desdetest/flutter_test_config.dartpara que se aplique a toda la suite:dartimport 'package:allure_dart_test/allure_dart_test.dart'; import 'package:test/test.dart'; void main() { installAllure(); test('login works', () async { await step('submit credentials', (_) async { expect(2 + 2, equals(4)); }); }); }dartimport 'dart:async'; import 'package:allure_flutter_test/allure_flutter_test.dart'; Future<void> testExecutable(FutureOr<void> Function() testMain) async { installAllure(); await testMain(); }Ambos estilos producen resultados de Allure y soportan la misma API de runtime. El estilo drop-in además reporta los callbacks de
setUp/tearDowncomo fixtures de Allure, convierte unskip:declarado en un auto-skip en tiempo de ejecución para que siga apareciendo en el reporte (ver Omitir pruebas), y puede omitir pruebas excluidas por un plan de pruebas.
2. Ejecuta las pruebas
Ejecuta tus pruebas como de costumbre:
dart testflutter testPor defecto, la integración escribe los resultados en un directorio allure-results en el directorio de trabajo actual.
WARNING
Estos adaptadores solo funcionan en la Dart VM — la plataforma predeterminada para dart test y flutter test. En navegadores o Node.js (dart test -p chrome, dart test -p node, flutter test --platform chrome), todas las pruebas fallan con el mensaje Allure cannot write test results on this platform (no filesystem), incluso aquellas que nunca llaman la API de Allure, porque los adaptadores siempre intentan escribir un archivo de resultado y no hay sistema de archivos disponible.
Para usar un directorio diferente, define ALLURE_RESULTS_DIR antes de la ejecución de pruebas:
ALLURE_RESULTS_DIR=build/allure-results dart testSi el directorio de resultados ya existe, los nuevos archivos se añaden a los existentes, de modo que un futuro reporte se basará en todos ellos.
3. Genera un reporte
Después de la ejecución de pruebas, genera y abre el reporte con la CLI de Allure:
allure generate ./allure-results --output ./allure-report --clean
allure open ./allure-reportSi cambiaste el directorio de resultados, usa esa ruta en el comando allure generate.
Escribir pruebas
Los adaptadores de Allure para Dart amplían la salida de dart test y flutter test con funciones de reporte enriquecidas. Puedes usarlos para:
- añadir descripciones, responsables, enlaces y otros metadatos,
- organizar las pruebas en jerarquías basadas en comportamiento y suites,
- dividir la ejecución en pasos anidados,
- describir parámetros y adjuntos,
- reportar fixtures de setup y limpieza,
- omitir pruebas sin perderlas del reporte,
- ejecutar solo pruebas seleccionadas mediante un archivo de plan de pruebas.
Añadir metadatos
Dentro del cuerpo de la prueba, usa las funciones de runtime para enriquecer el resultado de prueba:
import 'package:allure_dart_test/test.dart';
import 'package:allure_dart_test/allure_dart_test.dart' as allure;
void main() {
test('login works', () async {
await allure.displayName('Login works');
await allure.description('This test verifies login with a username and a password.');
await allure.owner('John Doe');
await allure.tag('smoke');
await allure.severity('critical');
await allure.allureId('AUTH-1');
await allure.issue('https://jira.example.com/browse/AUTH-123', name: 'AUTH-123');
await allure.tms('https://tms.example.com/cases/TMS-456', name: 'TMS-456');
});
}También puedes declarar metadatos de forma estática, sin modificar el cuerpo de la prueba. Los marcadores inline en el nombre de la prueba se analizan y eliminan del nombre para mostrar:
test('checkout works @allure.id:123 @allure.label.owner:payments', () async {
// ...
});Los marcadores soportados son @allure.id:<valor>, @allure.label.<nombre>:<valor>, @allure.link.<tipo>:<url>, y @allure.name:<nombre para mostrar> (= funciona igual que :).
Los tags normales de package:test se reportan como etiquetas tag de Allure. Los tags reservados @allure.* se tratan como metadatos inline y no se convierten en etiquetas tag:
test(
'checkout works',
() async {
// ...
},
tags: ['smoke'],
);Organizar pruebas
Allure soporta jerarquías tanto basadas en comportamiento como en suites. Por ejemplo:
test('login works', () async {
await allure.epic('Web interface');
await allure.feature('Authentication');
await allure.story('Login with username and password');
await allure.parentSuite('UI tests');
await allure.suite('Authentication');
await allure.subSuite('Positive scenarios');
});Los adaptadores también derivan etiquetas de suite automáticamente a partir de la jerarquía de group(). Las llamadas explícitas a allure.parentSuite(...), allure.suite(...) o allure.subSuite(...) sobrescriben las etiquetas derivadas automáticamente. Consulta Configuración para la lista completa de etiquetas automáticas.
Dividir una prueba en pasos
Envuelve partes de la prueba en pasos nombrados con allure.step(). Los pasos se anidan, registran su propio tiempo y estado, y pueden llevar parámetros:
test('login works', () async {
await allure.step('open login page', (_) async {
// ...
});
await allure.step('submit credentials', (step) async {
await step.parameter('user', 'alice');
await allure.step('fill the form', (_) async {
// ...
});
});
});Si el cuerpo de un paso lanza una excepción, el paso se reporta como fallido o roto, y el error se relanza, así que la prueba falla como de costumbre.
Para registrar una acción ya completada sin envolver código, usa allure.logStep():
await allure.logStep('verify audit log');Añadir parámetros y adjuntos
Los parámetros y adjuntos se almacenan en los resultados generados de Allure y se muestran en el reporte:
test('login works', () async {
await allure.parameter('browser', 'firefox');
await allure.parameter('password', 'qwerty', mode: allure.AllureParameterMode.masked);
await allure.attachment(
'request.json',
'{"username":"demo","rememberMe":true}',
contentType: 'application/json',
fileExtension: 'json',
);
await allure.attachmentPath(
'screenshot',
'screenshots/failure.png',
contentType: 'image/png',
);
});El contenido del adjunto puede ser un String, una lista de bytes o cualquier objeto codificable en JSON. Por defecto, los adjuntos añadidos desde dentro de una prueba se envuelven en un paso de adjunto, así mantienen su posición lógica entre los pasos circundantes; pasa wrapInStep: false para adjuntarlos directamente a la prueba o al paso actual.
INFO
Los cuerpos de testWidgets se ejecutan en una zona fake-async, así que una llamada a adjunto que haga I/O real (attachmentPath, o attachment con contenido de stream) debe ejecutarse dentro de tester.runAsync(...). Fuera de runAsync, la zona fake nunca bombea el callback de I/O real y la prueba se queda colgada.
Capturar fallos de Flutter automáticamente
installAllure() de allure_flutter_test acepta dos flags optativos solo para Flutter, que instalan un hook global la primera vez que cualquiera se pasa como true:
installAllure(
autoScreenshotOnFailure: true,
autoAttachGoldenDiff: true,
);autoScreenshotOnFailurecaptura una captura de pantalla del árbol de widgets cuando una prueba falla y la adjunta comoscreenshot-on-failure.autoAttachGoldenDiffadjunta la imagen renderizada actual comogolden-actual(además, en la medida de lo posible, las imágenes master y de prueba) cuando una comparaciónmatchesGoldenFilefalla.
Ambos hooks son best-effort — un fallo de captura nunca oculta el fallo original de la prueba — y monotónicos: una vez habilitados por cualquier llamada a installAllure(...) en el proceso, una llamada posterior sin flags no los deshabilita. Actívalos una vez, por ejemplo en test/flutter_test_config.dart. Consulta Referencia para más detalles.
Reportar fixtures
Cuando usas los imports drop-in, los callbacks de setUp, tearDown, setUpAll y tearDownAll se reportan como fixtures de Allure, mostrados en el reporte junto a las pruebas que preparan:
import 'package:allure_dart_test/test.dart';
import 'package:allure_dart_test/allure_dart_test.dart' as allure;
void main() {
group('authentication', () {
setUp(() async {
await allure.step('reset database', (_) async {
// ...
});
});
test('login works', () async {
// ...
});
});
}Los pasos y adjuntos creados dentro de un fixture se adjuntan al resultado del fixture. Las etiquetas y enlaces declarados dentro de un fixture de setUp o setUpAll se aplican a las pruebas en su alcance.
Omitir pruebas
En los wrappers drop-in, un skip: true declarado (o un mensaje de omisión) se convierte en un auto-skip en tiempo de ejecución, así la prueba sigue reportándose como omitida, no se pierde del reporte:
test('checkout applies a discount', () {
// ...
}, skip: true);Con installAllure() y los imports originales del framework, la misma declaración produce ningún resultado de Allure, porque el framework nunca ejecuta setUp para una prueba omitida por declaración, y ahí es donde el adaptador programa el resultado. Llama a markTestSkipped(...) desde el cuerpo de la prueba si necesitas un resultado omitido sin cambiar al import drop-in:
test('checkout applies a discount', () {
markTestSkipped('temporarily disabled');
});WARNING
Un group(..., skip: true) drop-in no se reenvía al skip de grupo del framework original — cada prueba anidada sigue ejecutándose lo suficiente para auto-omitir individualmente. Esto significa que los fixtures de setUp, setUpAll y tearDown dentro de un grupo omitido pueden ejecutarse, a diferencia de un skip de grupo por declaración, que nunca ejecuta los fixtures del grupo. Omite pruebas individuales en vez del grupo si los fixtures no deben ejecutarse.
Seleccionar pruebas mediante un archivo de plan de pruebas
Los adaptadores soportan el mecanismo estándar de plan de pruebas de Allure mediante la variable de entorno ALLURE_TESTPLAN_PATH.
Crea un archivo JSON como:
{
"version": "1.0",
"tests": [{ "id": "AUTH-1" }, { "selector": "test/auth_test.dart#authentication#login works" }]
}Luego ejecuta las pruebas con:
ALLURE_TESTPLAN_PATH=./testplan.json dart testLas entradas con id coinciden con pruebas que declaran un Allure ID, por ejemplo mediante el marcador @allure.id:AUTH-1. Las entradas con selector coinciden con el nombre completo de la prueba: la ruta del archivo de prueba, los nombres de grupo y el nombre de la prueba, unidos por #.
Cuando las pruebas se declaran mediante los wrappers drop-in test, group o testWidgets, las pruebas no incluidas en el plan se omiten por declaración: el cuerpo no se ejecuta y no se escribe ningún resultado de Allure. En suites que usan installAllure() con los imports originales del framework, las pruebas excluidas siguen ejecutándose, pero sus resultados se dejan fuera de allure-results.
Crear una integración personalizada
Si necesitas integrar Allure con un runner o framework de pruebas personalizado en Dart, usa allure_dart_commons:
dart pub add allure_dart_commonsEn ese nivel, creas un lifecycle, inicias un caso de prueba y lo detienes y escribes cuando termina la ejecución:
import 'package:allure_dart_commons/allure_dart_commons.dart';
Future<void> main() async {
final lifecycle = AllureLifecycle(
writer: AllureResultsWriter(outputDirectory: 'allure-results'),
);
final testUuid = lifecycle.startTest(
name: 'login works',
fullName: 'auth/login_test.dart#login works',
);
// ... actualizar metadatos, añadir pasos y adjuntos ...
await lifecycle.stopTest(testUuid, status: AllureStatus.passed);
await lifecycle.writeTest(testUuid);
}Consulta Referencia para las APIs de runtime y lifecycle, o Configuración para las variables de entorno soportadas y el archivo de configuración allure-dart.yaml.