Simular dependencias usando Mockito
Utiliza el paquete Mockito para imitar el comportamiento de los servicios para realizar pruebas.
A veces, las pruebas unitarias pueden depender de clases que obtienen datos de servicios web o bases de datos en vivo. Esto resulta inconveniente por varias razones:
- Llamar a servicios o bases de datos en vivo ralentiza la ejecución de las pruebas.
- Una prueba que pasa podría empezar a fallar si un servicio web o una base de datos devuelve resultados inesperados. Esto se conoce como una "prueba inestable" (flaky test).
- Es difícil probar todos los escenarios posibles de éxito y fallo utilizando un servicio web o una base de datos en vivo.
Por lo tanto, en lugar de depender de un servicio web o una base de datos en vivo, puedes "simular" (mock) estas dependencias. Los simuladores (mocks) permiten emular un servicio web o una base de datos en vivo y devolver resultados específicos según la situación.
En términos generales, puedes simular dependencias creando una implementación alternativa de una clase. Puedes escribir estas implementaciones alternativas a mano o utilizar el paquete Mockito como atajo.
Esta receta demuestra los conceptos básicos de la simulación con el paquete Mockito mediante los siguientes pasos:
- Añade las dependencias del paquete.
- Crea una función para probar.
- Crea un archivo de pruebas con un
http.Clientsimulado. - Escribe una prueba para cada condición.
- Ejecuta las pruebas.
Para más información, consulta la documentación del paquete Mockito.
1. Añade las dependencias del paquete
#Para usar el paquete mockito, añádelo al archivo pubspec.yaml junto con la dependencia flutter_test en la sección dev_dependencies.
Este ejemplo también utiliza el paquete http, así que define esa dependencia en la sección dependencies.
mockito: 5.0.0 es compatible con la seguridad nula (null safety) de Dart gracias a la generación de código. Para ejecutar la generación de código requerida, añade la dependencia build_runner en la sección dev_dependencies.
Para añadir las dependencias, ejecuta flutter pub add:
flutter pub add http dev:mockito dev:build_runner
2. Crea una función para probar
#En este ejemplo, realizarás una prueba unitaria de la función fetchAlbum de la receta
Obtener datos de internet.
Para probar esta función, realiza dos cambios:
- Proporciona un
http.Clienta la función. Esto permite proporcionar el correctohttp.Clientsegún la situación. Para Flutter y proyectos del lado del servidor, proporciona unhttp.IOClient. Para aplicaciones de navegador, proporciona unhttp.BrowserClient. Para las pruebas, proporciona unhttp.Clientsimulado. - Usa el
clientproporcionado para obtener datos de internet, en lugar del método estáticohttp.get(), que es difícil de simular.
La función ahora debería verse así:
Future<Album> fetchAlbum(http.Client client) async {
final response = await client.get(
Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
En el código de tu aplicación, puedes proporcionar un http.Client al método fetchAlbum
directamente con fetchAlbum(http.Client()). http.Client() crea un
http.Client por defecto.
3. Crea un archivo de pruebas con un http.Client simulado
#
A continuación, crea un archivo de pruebas.
Siguiendo los consejos de la receta Introducción a las pruebas unitarias,
crea un archivo llamado fetch_album_test.dart en la carpeta raíz test.
Añade la anotación
@GenerateMocks([], customMocks: [MockSpec<http.Client>(as: #MockHttpClient)])
a la función principal para generar una clase MockHttpClient con mockito.
La clase MockHttpClient generada implementa la clase http.Client.
Esto te permite pasar el MockHttpClient a la función fetchAlbum,
y devolver diferentes respuestas http en cada prueba.
Los mocks generados se ubicarán en fetch_album_test.mocks.dart.
Importa este archivo para usarlos.
import 'package:http/http.dart' as http;
import 'package:mocking/main.dart';
import 'package:mockito/annotations.dart';
// Generate a MockClient using the Mockito package.
// Create new instances of this class in each test.
// Note: Naming the generated mock `MockHttpClient` to avoid confusion with
// `MockClient` from `package:http/testing.dart`.
@GenerateMocks([], customMocks: [MockSpec<http.Client>(as: #MockHttpClient)])
void main() {
}
A continuación, genera los mocks ejecutando el siguiente comando:
dart run build_runner build
4. Escribe una prueba para cada condición
#La función fetchAlbum() hace una de dos cosas:
- Devuelve un
Albumsi la llamada http tiene éxito - Lanza una
Exceptionsi la llamada http falla
Por lo tanto, quieres probar estas dos condiciones.
Usa la clase MockHttpClient para devolver una respuesta "Ok"
para la prueba de éxito, y una respuesta de error para la prueba fallida.
Prueba estas condiciones utilizando la función when() proporcionada por
Mockito:
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:mocking/main.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'fetch_album_test.mocks.dart';
// Generate a MockClient using the Mockito package.
// Create new instances of this class in each test.
// Note: Naming the generated mock `MockHttpClient` to avoid confusion with
// `MockClient` from `package:http/testing.dart`.
@GenerateMocks([], customMocks: [MockSpec<http.Client>(as: #MockHttpClient)])
void main() {
group('fetchAlbum', () {
test('returns an Album if the http call completes successfully', () async {
final client = MockHttpClient();
// Use Mockito to return a successful response when it calls the
// provided http.Client.
when(
client.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')),
).thenAnswer(
(_) async =>
http.Response('{"userId": 1, "id": 2, "title": "mock"}', 200),
);
expect(await fetchAlbum(client), isA<Album>());
});
test('throws an exception if the http call completes with an error', () {
final client = MockHttpClient();
// Use Mockito to return an unsuccessful response when it calls the
// provided http.Client.
when(
client.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')),
).thenAnswer((_) async => http.Response('Not Found', 404));
expect(fetchAlbum(client), throwsException);
});
});
}
5. Ejecuta las pruebas
#Ahora que tienes una función fetchAlbum() con pruebas en su lugar,
ejecuta las pruebas.
flutter test test/fetch_album_test.dart
También puedes ejecutar pruebas dentro de tu editor favorito siguiendo las instrucciones de la receta Introducción a las pruebas unitarias.
Ejemplo completo
#lib/main.dart
#import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum(http.Client client) async {
final response = await client.get(
Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
const Album({required this.userId, required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'] as int,
id: json['id'] as int,
title: json['title'] as String,
);
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late final Future<Album> futureAlbum;
@override
void initState() {
super.initState();
futureAlbum = fetchAlbum(http.Client());
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: Scaffold(
appBar: AppBar(title: const Text('Fetch Data Example')),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
test/fetch_album_test.dart
#import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:mocking/main.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'fetch_album_test.mocks.dart';
// Generate a MockClient using the Mockito package.
// Create new instances of this class in each test.
// Note: Naming the generated mock `MockHttpClient` to avoid confusion with
// `MockClient` from `package:http/testing.dart`.
@GenerateMocks([], customMocks: [MockSpec<http.Client>(as: #MockHttpClient)])
void main() {
group('fetchAlbum', () {
test('returns an Album if the http call completes successfully', () async {
final client = MockHttpClient();
// Use Mockito to return a successful response when it calls the
// provided http.Client.
when(
client.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')),
).thenAnswer(
(_) async =>
http.Response('{"userId": 1, "id": 2, "title": "mock"}', 200),
);
expect(await fetchAlbum(client), isA<Album>());
});
test('throws an exception if the http call completes with an error', () {
final client = MockHttpClient();
// Use Mockito to return an unsuccessful response when it calls the
// provided http.Client.
when(
client.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')),
).thenAnswer((_) async => http.Response('Not Found', 404));
expect(fetchAlbum(client), throwsException);
});
});
}
Resumen
#En este ejemplo, has aprendido a utilizar Mockito para probar funciones o clases que dependen de servicios web o bases de datos. Esto es solo una breve introducción a la biblioteca Mockito y al concepto de simulación (mocking). Para obtener más información, consulta la documentación proporcionada por el paquete Mockito.
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.