flutter_mockkit
A lightweight, developer-friendly toolkit to mock API requests and responses in Flutter apps during development.
Stop waiting for a backend. With flutter_mockkit you can:
- Intercept every HTTP call from
httpanddioclients. - Return static or dynamically computed responses.
- Simulate realistic network latency and hard failures.
- Toggle between mock and live mode with a single line of code.
- Generate realistic fake data from a JSON schema β no extra dependencies.
Table of Contents
- Features
- Installation
- Quick Start
- Usage Guide
- API Reference
- Publishing to pub.flutter-io.cn
- Contributing
- License
Features
| Feature | Description |
|---|---|
| π Mock / Live Toggle | MockKit.enable() / MockKit.disable() β flip the switch globally. |
| π http & dio Support | MockHttpClient and MockDioInterceptor are drop-in replacements. |
| β‘ Dynamic Responses | Pass a responseBuilder function to compute responses at request time. |
| π£οΈ Path Parameters | Routes like /users/:id extract params automatically. |
| β³ Delay Simulation | Per-route and global artificial latency. |
| π₯ Error Simulation | Return 4xx/5xx or throw network exceptions deterministically. |
| 𧬠Data Generator | Generate fake users, products, UUIDs, emails β from a schema map. |
| π Paginated Lists | One-liner helper for paginated REST list responses. |
| π Verbose Logging | Opt-in console log for every intercepted request and its outcome. |
Installation
Add flutter_mockkit to your pubspec.yaml:
dependencies:
flutter_mockkit: ^1.0.0
Then run:
flutter pub get
Tip: Consider adding this only to
dev_dependenciesif you wrap the mock setup behind a build-time flag so mocks are never shipped to production.
Quick Start
import 'package:flutter_mockkit/flutter_mockkit.dart';
import 'package:dio/dio.dart';
void main() {
// 1. Enable mock mode
MockKit.enable();
// 2. Register a mock route
MockKit.register(MockRoute(
method: HttpMethod.get,
path: '/users',
response: MockResponse.ok({'users': [{'id': 1, 'name': 'Alice'}]}),
));
// 3. Attach the interceptor to your Dio client
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
dio.interceptors.add(MockDioInterceptor());
runApp(MyApp(dio: dio));
}
That's it β every GET /users call now returns your mock data, zero network
traffic involved.
Usage Guide
1. Enabling / Disabling Mock Mode
// Enable β all registered mocks are active
MockKit.enable();
// Disable β requests pass through to the real network
MockKit.disable();
// Check current state
print(MockKit.isEnabled); // true / false
A common pattern is to gate this on your build mode:
if (kDebugMode) MockKit.enable();
2. Basic GET Mock
MockKit.register(MockRoute(
method: HttpMethod.get,
path: '/products',
description: 'Returns the product catalogue', // optional β for your notes
response: MockResponse.ok([
{'id': 1, 'name': 'Widget A', 'price': 9.99},
{'id': 2, 'name': 'Widget B', 'price': 19.99},
]),
));
Convenience response factories:
MockResponse.ok(body) // 200
MockResponse.created(body) // 201
MockResponse.badRequest() // 400
MockResponse.unauthorized() // 401
MockResponse.notFound() // 404
MockResponse.serverError() // 500
MockResponse.networkFailure() // throws MockNetworkException
3. Basic POST Mock
MockKit.register(MockRoute(
method: HttpMethod.post,
path: '/products',
response: MockResponse.created({'id': 42, 'name': 'New Widget'}),
));
4. Dynamic Responses
Use a responseBuilder to inspect the request before deciding what to return.
The builder receives a MockRequest with body, queryParameters,
headers, and pathParameters already parsed.
MockKit.register(MockRoute(
method: HttpMethod.post,
path: '/login',
responseBuilder: (request) {
final body = request.bodyAsJson; // Map<String, dynamic>
if (body['password'] == 'secret') {
return MockResponse.ok({'token': 'jwt-abc-123'});
}
return MockResponse.unauthorized();
},
));
5. Path Parameters
Routes support :name style path parameters. They are extracted and passed
into MockRequest.pathParameters.
// Route: /users/:id
MockKit.register(MockRoute(
method: HttpMethod.get,
path: '/users/:id',
responseBuilder: (request) {
final id = request.pathParameters['id']!; // '42'
return MockResponse.ok({'id': id, 'name': 'User $id'});
},
));
// Matches:
// GET /users/1
// GET /users/42
// GET /users/abc123
Multi-segment parameters also work:
MockKit.register(MockRoute(
method: HttpMethod.get,
path: '/teams/:teamId/members/:memberId',
responseBuilder: (request) {
return MockResponse.ok({
'team': request.pathParameters['teamId'],
'member': request.pathParameters['memberId'],
});
},
));
6. Simulated Latency
Per-route delay
MockKit.register(MockRoute(
method: HttpMethod.get,
path: '/reports/annual',
response: MockResponse.ok(
{'report': 'dataβ¦'},
delay: const Duration(seconds: 2), // simulate a slow query
),
));
Global delay (added to every response)
// Add 300 ms to every mock response β great for testing loading states
MockKit.setGlobalDelay(const Duration(milliseconds: 300));
7. Error Simulation
Return any 4xx / 5xx status code to test your error-handling UI:
// 503 Service Unavailable
MockKit.register(MockRoute(
method: HttpMethod.get,
path: '/maintenance',
response: MockResponse(
statusCode: 503,
body: {'message': 'Under maintenance'},
),
));
Use the built-in factories for the most common cases:
MockResponse.notFound() // 404 {"error": "Not Found"}
MockResponse.serverError() // 500 {"error": "Internal Server Error"}
MockResponse.unauthorized() // 401 {"error": "Unauthorized"}
8. Network Failure Simulation
Simulates a hard network failure (throws an exception rather than returning an HTTP response):
MockKit.register(MockRoute(
method: HttpMethod.get,
path: '/flaky-endpoint',
response: MockResponse.networkFailure(
message: 'No internet connection',
),
));
With MockHttpClient this throws a MockNetworkException.
With MockDioInterceptor this triggers a DioException.
Handle it the same way you would handle a real network error:
try {
final response = await dio.get('/flaky-endpoint');
} on DioException catch (e) {
showErrorSnackBar('Network error: ${e.message}');
}
9. Using with the http Package
Replace http.Client() with MockHttpClient() β the API is identical:
import 'package:http/http.dart' as http;
import 'package:flutter_mockkit/flutter_mockkit.dart';
final http.Client client = MockHttpClient();
final response = await client.get(
Uri.parse('https://api.example.com/users'),
);
print(response.statusCode); // 200
print(response.body); // {"users": [...]}
When MockKit.isEnabled is false, or when no matching route is found, every
request is forwarded to the real network via the inner http.Client.
10. Using with Dio
Add MockDioInterceptor as the first interceptor on your Dio instance:
import 'package:dio/dio.dart';
import 'package:flutter_mockkit/flutter_mockkit.dart';
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
dio.interceptors.add(MockDioInterceptor()); // β add first
final response = await dio.get('/users');
print(response.data); // already decoded JSON
When mock mode is disabled or no route matches, MockDioInterceptor calls
handler.next(options) and Dio proceeds normally.
11. Auto-Generating Mock Data
MockDataGenerator turns a simple schema map into realistic fake data.
Single object
final user = MockDataGenerator.fromSchema({
'id': 'uuid',
'name': 'name',
'email': 'email',
'phone': 'phone',
'age': 'int',
'score': 'double',
'active': 'bool',
'joined': 'date',
'profile': 'url',
'bio': 'paragraph',
});
// {id: 'a1b2β¦', name: 'Alice Chen', email: 'alice.chen@example.com', β¦}
Supported type strings:
| Type string | Example output |
|---|---|
"string" |
"alpha" |
"int" / "integer" |
42 |
"double" / "float" |
73.41 |
"bool" / "boolean" |
true |
"uuid" / "id" |
"a1b2c3d4-β¦" |
"name" |
"Grace Harris" |
"email" |
"grace.harris@mail.io" |
"phone" |
"+1-415-555-1234" |
"date" |
"2022-08-15" |
"datetime" |
"2022-08-15T09:30:00.000" |
"url" / "uri" |
"https://example.com/api/v1/β¦" |
"color" / "colour" |
"#A3F2BC" |
"paragraph" / "text" |
Short lorem-ipsum sentence(s) |
List of objects
final users = MockDataGenerator.listFromSchema(
{'id': 'uuid', 'name': 'name', 'email': 'email'},
count: 10,
);
Paginated response
final page = MockDataGenerator.paginatedList(
schema: {'id': 'uuid', 'title': 'string', 'price': 'double'},
page: 2,
perPage: 10,
total: 57,
);
// {
// "data": [{β¦}, {β¦}, β¦],
// "pagination": {
// "page": 2, "per_page": 10, "total": 57,
// "total_pages": 6, "has_next": true, "has_prev": true
// }
// }
Wrap existing JSON as a MockResponse
final response = MockDataGenerator.fromJson(
{'token': 'eyJhbGciβ¦', 'expires_in': 3600},
statusCode: 200,
delay: const Duration(milliseconds: 200),
);
Individual primitive generators
MockDataGenerator.uuid(); // "f47ac10b-β¦"
MockDataGenerator.name(); // "James Lopez"
MockDataGenerator.email(); // "james.lopez@test.dev"
MockDataGenerator.phone(); // "+1-303-721-4892"
MockDataGenerator.date(); // "2021-03-18"
MockDataGenerator.datetime(); // "2021-03-18T14:22:00.000"
MockDataGenerator.url(); // "https://mockserver.io/api/v1/β¦"
MockDataGenerator.hexColor(); // "#E4A0F7"
MockDataGenerator.paragraph(); // "Lorem ipsum dolorβ¦"
MockDataGenerator.randomInt(min: 1, max: 100); // 57
MockDataGenerator.randomDouble(min: 0.0, max: 10.0); // 3.74
MockDataGenerator.randomBool(); // false
MockDataGenerator.pickOne(['a', 'b', 'c']); // "b"
12. Verbose Logging
Enable during development to see every intercepted call in the console:
MockKit.enableLogging();
// Console output:
// [MockKit] Registered mock: GET /users
// [MockKit] [MOCK] GET /users β 200
// [MockKit] [FAIL] GET /network-failure β Simulated network failure
API Reference
MockKit
| Member | Description |
|---|---|
MockKit.enable() |
Activates mock mode. |
MockKit.disable() |
Deactivates mock mode; requests hit the real network. |
MockKit.isEnabled |
Whether mock mode is active. |
MockKit.register(route) |
Registers (or replaces) a MockRoute. |
MockKit.registerAll(routes) |
Registers a list of MockRoutes. |
MockKit.unregister(method, path) |
Removes a specific route. |
MockKit.clearAll() |
Removes all registered routes. |
MockKit.routes |
Read-only list of all registered routes. |
MockKit.setGlobalDelay(duration) |
Adds latency to all mock responses. |
MockKit.globalDelay |
Current global delay. |
MockKit.enableLogging() |
Turns on verbose console logging. |
MockKit.disableLogging() |
Turns off verbose console logging. |
MockKit.resolve(method, path, β¦) |
Low-level resolver; returns MockResponse?. |
MockRoute
MockRoute({
required HttpMethod method,
required String path, // supports :param notation
MockResponse? response,
MockResponse Function(MockRequest)? responseBuilder,
String? description,
})
MockResponse
MockResponse({
int statusCode = 200,
dynamic body,
Map<String, String> headers,
Duration delay = Duration.zero,
bool shouldFail = false,
String? failureMessage,
})
Factory constructors: ok, created, badRequest, unauthorized,
notFound, serverError, networkFailure.
MockRequest
| Field | Type | Description |
|---|---|---|
path |
String |
Clean request path (no query string). |
method |
HttpMethod |
HTTP method. |
queryParameters |
Map<String, String> |
Parsed query params. |
headers |
Map<String, String> |
Request headers. |
body |
String? |
Raw request body. |
pathParameters |
Map<String, String> |
Extracted :param values. |
bodyAsJson |
Map<String, dynamic> |
Body decoded as JSON map. |
MockDataGenerator
Static utility β no instantiation required.
| Method | Returns |
|---|---|
fromJson(json) |
MockResponse wrapping any JSON object. |
fromSchema(schema) |
Map<String, dynamic> generated from a type-map. |
listFromSchema(schema, {count}) |
List<Map<String, dynamic>>. |
paginatedList({schema, page, perPage, total}) |
Paginated envelope map. |
uuid() |
UUID v4-style string. |
name() |
Full name string. |
email() |
Email address string. |
phone() |
Phone number string. |
date() |
ISO-8601 date string. |
datetime() |
ISO-8601 datetime string. |
url() |
HTTPS URL string. |
hexColor() |
Hex color string. |
paragraph() |
Short lorem paragraph. |
randomInt({min, max}) |
Random int. |
randomDouble({min, max}) |
Random double. |
randomBool() |
Random bool. |
pickOne(items) |
Random element from items. |
Publishing to pub.flutter-io.cn
Follow these steps to publish flutter_mockkit to pub.flutter-io.cn:
1. Prerequisites
- Dart SDK β₯ 3.0 installed.
- A Google account linked to pub.flutter-io.cn.
2. Update pubspec.yaml
Edit the following fields before publishing:
name: flutter_mockkit
version: 1.0.0 # β bump on each release
homepage: https://github.com/YOU/flutter_mockkit
repository: https://github.com/YOU/flutter_mockkit
3. Verify the package
dart pub publish --dry-run
Fix every warning/error reported. Common issues:
| Issue | Fix |
|---|---|
Missing LICENSE |
Add an MIT or BSD LICENSE file. |
| Low pub score | Add doc-comments (///) to all public APIs. |
Missing example/ |
Ensure example/main.dart exists. |
| SDK constraint | Set sdk: ">=3.0.0 <4.0.0". |
4. Check your pub score locally
dart pub global activate pana
pana .
Aim for 130/140 or higher before publishing.
5. Publish
dart pub publish
You will be prompted to authenticate via your browser.
6. Subsequent releases
- Update
versioninpubspec.yaml. - Add a new entry to
CHANGELOG.md. - Run
dart pub publish --dry-runagain. - Run
dart pub publish.
Contributing
Contributions, bug reports and feature requests are welcome!
- Fork the repo.
- Create a branch:
git checkout -b feat/my-feature. - Commit your changes:
git commit -m 'feat: add my feature'. - Push:
git push origin feat/my-feature. - Open a Pull Request.
Please run flutter test and dart analyze before submitting a PR.
License
This project is licensed under the MIT License.
Libraries
- flutter_mockkit
- flutter_mockkit β A lightweight dev toolkit for mocking API requests and responses during Flutter development.