Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test - How to mock parameters of third-party-library class Dio in flutter

I am trying to test a simple repository class which make a network call using the Dio package that is a dependency injection. Requirement of the Http.post is to send a Map object to a URL with the headers of 'Content-Type': 'application/json. You can see this below:

class AuthenticateUserRemoteDataSourceImpl
    implements AuthenticateUserRepository {
  final Dio httpClient;

  AuthenticateUserRemoteDataSourceImpl({@required this.httpClient});

  @override
  Future<Either<Failure, AuthenticateUser>> getAuthenticateUser(
      String email, String password) async {
    final url = 'API_URL';

    final Map<String, String> jsonPayload = {
      "email": email,
      "password": password
    };

    Response response = await httpClient.post('{$url}api/users/authenticate',
        data: jsonPayload,
        options: Options(headers: {'Content-Type': 'application/json'}));
  }
}

I am trying to make sure this method is covered by unit test, however I am having difficult verify the named parameters with the Dio package. I can verify that the dioClient.post is actually called however, I am having trouble with mocking the name parameters of 'data' and 'options'.

I want to test that it gets called with Map<String, String> for the body, and also I would like to test the headers that are sent, I want to check that is it called with the {'Content-Type': 'application/json'}. This will be useful as well when I need to unit test Authenticated dio get/post/put requests.

This is the test that I have so far, which as mentioned before I can verify that the mocked function is called, but not verifying the name params.


  group('getAuthenticateUser', () {
    final tResponse = Response(statusCode: 200, data: {"title": "success"});

    test(
        'should perform a post request to the the API with the application/json header',
        () async {
      // arrange
      when(dioClient.post(any,
              data: anyNamed('data'), options: anyNamed('options')))
          .thenAnswer((Invocation invocation) async => tResponse);

      // act
      await dataSource.getAuthenticateUser(tEmail, tPassword);

      // assert
      verify(dioClient.post(any,
          data: anyNamed('data'), options: anyNamed('options')));
    });
  });

Thanks for your helps, I am just getting started with unit testing so any help or pointers will be great,

Thanks, Sam

@LoVe enter image description here

Update

I have implemented your mock class which worked great, and I think it was the thing that I was missing for sure. I have updated my test but cannot understand where I am going wrong now?

test.dart

class MockOptions extends Mock implements Options {
  final Map<String, dynamic> headers;
  //also add any other parameters you want to mock as fields in this class

  MockOptions({this.headers});
}


test(
   'should perform a post request to the the API with the application/json header',
    () async {
        // arrange
        Map<String, String> headers = {'Content-type': 'application/json'};

        when(mockDio.post('path', options: anyNamed('options')))
          .thenAnswer((_) async => Response(data: {}));

        // act
        dataSource.getAuthenticateUser(tEmail, tPassword);

        // assert
        verify(mockDio.post('path', options: MockOptions(headers: headers)));
    });

and the method file looking like this:

  @override
  Future<Either<Failure, AuthenticateUser>> getAuthenticateUser(
      String email, String password) async {

    await this.httpClient.post('path',
        data: {},
        options: Options(headers: {'Content-type': 'application/json'}));
  }
like image 226
Sam Kelham Avatar asked Dec 18 '25 19:12

Sam Kelham


2 Answers

Use http_mock_adapter, new package for mocking Dio requests.

You can simply replace your injected Dio's httpClientAdapter with DioAdapter() of http_mock_adapter:

example from examples of http_mock_adapter

import 'package:dio/dio.dart';
import 'package:http_mock_adapter/http_mock_adapter.dart';

void main() async {
  final dio = Dio();
  final dioAdapter = DioAdapter();

  dio.httpClientAdapter = dioAdapter;

  const path = 'https://example.com';

  dioAdapter
      ..onGet(
        path,
        (request) => request.reply(200, {'message': 'Successfully mocked GET!'}),
      )
      ..onGet(
        path,
        (request) => request.reply(200, {'message': 'Successfully mocked POST!'}),
      );

  final onGetResponse = await dio.get(path);
  print(onGetResponse.data); // {message: Successfully mocked GET!}

  final onPostResponse = await dio.post(path);
  print(onPostResponse.data); // {message: Successfully mocked POST!}
}

You can also use, DioInterceptor of http_mock_adapter, which can be added to dio.interceptor list.

view second example in examples file of http_mock_adapter

like image 129
man of knowledge Avatar answered Dec 20 '25 09:12

man of knowledge


to test that this method

Response response = await httpClient.post('{$url}api/users/authenticate',
        data: jsonPayload,
        options: Options(headers: {'Content-Type': 'application/json'}));

is called with proper arguments you should create an MockOption class and pass an instance of it to the function call in your test

also you should create an object of type Map<String,dynamic> (or whatever types the json uses) and pass that object also to the same method call to the data parameter

then you use Mockito's methods to verify that your method was called with the test arguments you have passed

and also to test the headers you do as I said here regarding the map:

also you should create an object of type Map<String,dynamic> (or whatever types the json uses) and pass that object also to the same method call

Please have a look at my answer here

Update:

so for example to mock the options parameter you can do:

class MockOptions extends Mock implements Options{
  final Map<String,dynamic> headers;
  //also add any other parameters you want to mock as fields in this class

  MockOptions(this.headers);
}

then, in your test, you do:

final MockOptions mockOptions = MockOptions({
              //mocked map data here
            });
like image 28
Haidar Avatar answered Dec 20 '25 11:12

Haidar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!