0

I'm trying to setup a test for a super simple post request and mockito's "verify" method fails to identify assert that the method was actually called when the body is decoded.

The test runs perfectly fine when both - test and implementation - are like the following:

// lots of other imports
import 'auth_data_source_test.mocks.dart';

@GenerateMocks([http.Client])
void main() {
  late AuthRemoteDataSourceImpl datasource;
  late MockClient mockHttClient;

  setUp(() {
    mockHttClient = MockClient();
    datasource = AuthRemoteDataSourceImpl(client: mockHttClient);
  });

  group('login', () {
    const tUsername = 'user@example.com';
    const tPassword = 'myPassword';
    const tEndpoint = 'http://app.griot.me/api/user/auth/';
    const tBody = {
      "username": tUsername,
      "password": tPassword,
    };

    const tHeaders = {
      'Content-Type': 'application/json',
    };
    final tTokenModel =
        TokenModel.fromJson(json.decode(fixture('auth_success_response.json')));

    test(
      'Should perform a POST request with user/auth/ endpoint and application/jason header',
      () async {
        // arrange
        when(mockHttClient.post(Uri.parse(tEndpoint),
                headers: tHeaders, body: tBody))
            .thenAnswer((_) async =>
                http.Response(fixture('auth_success_response.json'), 200));

        datasource.login(tUsername, tPassword);
        // assert
        verify(mockHttClient.post(Uri.parse(tEndpoint),
            headers: tHeaders,
            body: {'username': tUsername, 'password': tPassword}));
      },
    );

and the tested file is

// lots of imports

abstract class AuthRemoteDataSource {
  Future<TokenModel> login(String username, String password);
  Future<void> storeToken(TokenModel tokenToStore);
}

class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
  final http.Client client;

  AuthRemoteDataSourceImpl({required this.client});

  @override
  Future<TokenModel> login(String username, String password) async {
    final Map<String, dynamic> body = {
      'username': username,
      'password': password,
    };

    final response =
        await client.post(Uri.parse('http://app.griot.me/api/user/auth/'),
            headers: {
              'Content-Type': 'application/json',
            },
            body: body);

    await handleError(response);

    return TokenModel.fromJson(json.decode(response.body));
  }

  @override
  Future<void> storeToken(TokenModel tokenToStore) async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('token', tokenToStore.tokenString);
  }

  Future<void> handleError(http.Response response) async {
    if (response.statusCode == 401 || response.statusCode == 404) {
      throw InvalidTokenException();
    } else if (!(response.statusCode >= 200 && response.statusCode <= 204)) {
      throw ServerException();
    }
  }
}

but, if I change, (as I need to) the implementation to use jsonEncode in the body

final response =
    await client.post(Uri.parse('http://app.griot.me/api/user/auth/'),
        headers: {
          'Content-Type': 'application/json',
        },
        body: jsonEncode(body));

and the test to also expect a encoded body

    when(mockHttClient.post(Uri.parse(tEndpoint),
            headers: tHeaders, body: jsonEncode(tBody)))
        .thenAnswer((_) async =>
            http.Response(fixture('auth_success_response.json'), 200))

I get the following error: No matching calls. All calls: MockClient.post(http://app.griot.me/api/user/auth/, {headers: {Content-Type: application/json}, body: {"username":"user@example.com","password":"myPassword"}, encoding: null})

I tried regenerating the Mock files by running dart run build_runner build again I couldn't find a similar issue here.

1 Answers1

0

The problem was that the verify was checking for a {"username": "user@exemple.com","password": "myPassword"} and yet, when encoding it it changed to "{"username": "user@exemple.com","password": "myPassword"}"

To avoid getting into that small issues I changed to

verify(mockHttClient.post(
          Uri.parse(tEndpoint),
          headers: tHeaders,
          body: jsonEncode(tBody),
        )