-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Selective mocking #136
Comments
You mean to have some real routes and some mocked ones together ? |
I found a solution to do that. We could create another Dio object for remote API callings. |
@HeLinChooi thats the approach i did as well. Specifically, I have an |
In the Javascript world, there is the MSW package which lets you define if it should match all the routes or just the defined ones. It's a common usecase for development to only want to mock a new (non-existent) endpoint in order to already develop without having a working backend and let the other routes go to the existing back-end as usual. Such a feature would increase the value of this package by a lot! Is it possible to add such a config parameter or would it require much more work? |
Thanks, Sebastian for the suggestion! |
I think the proposed solution @HeLinChooi is not optimal as it requires the ability to switch out the DIO object for a single call in my proposed usecase. Let's say you have a service with 10 calls and you want to add a new call there. Then you would have to integrate the mocked DIO object to the service, add the handler for the mock and build the new call on top of that. In the approach of MSW you will always use the same DIO object and if the call does not match to any mocked handler it will just be called as usual with the real DIO object. At the moment here is the condition if the route is not matched for a call and it always throws an exception. For development usage here it would be super nice to have a settings flag in order to choose: a) throw exception or b) route call to original DIO object. Do you see my point? |
I implemented a simple selective mocking class like this: import 'package:dio/dio.dart';
import 'package:kasparund/mocks/mock_handlers.dart';
/// Interceptor for mocking API responses
///
/// This interceptor will intercept all requests and check if there is a mock
/// response for the request. If there is, it will return the mock response.
/// Otherwise, it will continue with the request as normal.
///
/// The mock responses are defined in [mockRoutes].
///
/// The [apiBaseURL] is used to match the request URL to the mock response.
///
/// Usage:
///
/// ```dart
/// final dio = Dio();
/// dio.interceptors.add(
/// DioMockInterceptor(apiBaseURL: 'https://example.com'),
/// );
/// ```
///
/// See also:
///
/// * [mockRoutes], which contains the mock responses
class DioMockInterceptor extends Interceptor {
final String apiBaseURL;
DioMockInterceptor({required this.apiBaseURL});
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
final routeKey = '${options.method}:${options.path}';
if (mockRoutes.containsKey(routeKey)) {
final response = mockRoutes[routeKey]!(options);
handler.resolve(response);
} else {
handler.next(options);
}
}
} You can then define the routes here: import 'package:dio/dio.dart';
/// Mocked routes for testing
///
/// This is a map of routes to mocked responses. The key is a string
/// in the format of `METHOD:PATH`, where `METHOD` is the HTTP method
/// (e.g. `GET`, `POST`, etc.) and `PATH` is the path of the request
/// (e.g. `api/users`, `api/users/123`, etc.).
///
/// The value is a function that takes a `RequestOptions` object and
/// returns a `Response` object. The `RequestOptions` object contains
/// the request information, such as the HTTP method, path, headers,
/// and body. The `Response` object contains the response information,
/// such as the status code and body.
///
/// For example, the following route will return a 200 response with
/// the body `{'message': 'Mocked GET response'}` for any `GET` request
/// to the path `/test`:
///
/// ```dart
/// 'GET:test': (RequestOptions options) {
/// return Response(
/// requestOptions: options,
/// data: {'message': 'Mocked GET response'},
/// statusCode: 200,
/// );
/// ```
final Map<String, Response Function(RequestOptions)> mockRoutes = {
'GET:test/123': (RequestOptions options) {
return Response(
requestOptions: options,
data: {'message': 'Mocked GET response'},
statusCode: 200,
);
},
// Add more routes as needed
}; And then add it to the // Add mock handlers if in debug mode
if (kDebugMode) {
dio.interceptors.add(DioMockInterceptor(apiBaseURL: config.apiBaseURL));
} Really like it for development. |
I would be more than happy if you could make a PR 💟 |
I tried at first, but I think it would require some major adjustments to the package, as currently, it will replace some core functionality of dio completely by overriding the I saw that in here we could add the feature if a non-matched call should throw an error or go back to original dio, but If somebody has an idea on how to combine those two approaches I would be happy to try again. One thing I saw in the MSW library: They use two different approaches for unit testing and development mocking, but maybe that's also because of the browser vs node.js implementation. However, we could think here as well, if we want a second approach that's more focused on development mocking instead of unit testing. |
I've been looking for a solution to this recently - and now found this thread - great to know I am not alone in wishing for this :-). I support the request to have this combined real & mock API capability in the same Dio instance - essentially it behaves as a real Dio (making requests to the remote endpoint) except when a mock-override is defined. The partial solution that @sebastianbuechler offers gave me an idea - I have adapted it so that the mocked routes can be specified in a JSON file that is loaded via assets. There is a demo of it here: https://github.com/eggzotic/mock_some_demo. It means that when you've completed all your mocking and all routes are now "real", all you have to do is remove the mocked routes from config.json (leaving its content as an empty |
Added the ability for selective mocking via #159 and will be available in the next release. Usage: Be aware that this flag is only available through the |
Description
During development, it's super useful to only mock certain endpoints - like new endpoints that don't exist yet. Right now from what I can tell it's either you mock every single endpoint or completely turn it off.
The text was updated successfully, but these errors were encountered: