Home > Net >  Mocktail: type 'Null' is not a subtype of type 'Future<Response>'
Mocktail: type 'Null' is not a subtype of type 'Future<Response>'

Time:11-09

I've been trying to test my API Provider following the Weather tutorial by Felangel since it's quite similar to my code, but I can't make it work.

api_provider_test.dart

import 'package:stock_mobile/data/models/user.dart';
import 'package:test/test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:http/http.dart' as http;
import 'package:stock_mobile/data/providers/api_provider.dart';

class MockHttpClient extends Mock implements http.Client {}

class MockResponse extends Mock implements http.Response {}

class FakeUri extends Fake implements Uri {}

void main() {
  group('ApiProvider', () {
    late http.Client httpClient;
    late ApiProvider apiProvider;

    setUpAll(() {
      registerFallbackValue(FakeUri());
    });

    setUp(() {
      httpClient = MockHttpClient();
      apiProvider = ApiProvider(httpClient: httpClient);
    });

    group('login', () {
      test('Throws ApiException non-200 response', () async {
        final response = MockResponse();

        when(() => response.statusCode).thenReturn(400);
        when(() => response.body).thenReturn('');
        when(() => httpClient.post(any())).thenAnswer((_) async => response);

        final actual = await apiProvider.login(const User.empty());

        expect(actual, throwsException);
      });
    });
  });
}

api_provider.dart

import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:stock_mobile/data/models/user.dart';

class ApiProvider {
  ApiProvider({http.Client? httpClient})
      : _httpClient = httpClient ?? http.Client();

  static const _baseUrl = '192.168.0.5:3000';
  final http.Client _httpClient;

  Future<String> login(User user) async {
    final loginRequest = Uri.http(_baseUrl, '/login');

    final loginResponse = await _httpClient.post(loginRequest, body: {
      "username": user.username,
      "password": user.password,
    });

    if (loginResponse.statusCode != 200) {
      throw Exception();
    }

    return jsonDecode(loginResponse.body);
  }
}

user.dart

import 'package:equatable/equatable.dart';

class User extends Equatable {
  const User(this.username, this.password);

  final String username;
  final String password;

  const User.empty({
    this.username = '',
    this.password = '',
  });

  @override
  String toString() {
    return 'User{username: $username, password: $password}';
  }

  @override
  List<Object?> get props => [username, password];
}

And when I try to run the code, I get this error:

package:http/src/client.dart 62:20                            MockHttpClient.post
package:stock_mobile/data/providers/api_provider.dart 17:45  ApiProvider.login
test\unit\api_provider_test.dart 42:42                             main.<fn>.<fn>.<fn>
test\unit\api_provider_test.dart 35:52                             main.<fn>.<fn>.<fn>

type 'Null' is not a subtype of type 'Future<Response>'

Then, I tried to fix it by adding when(() => apiProvider.login(const User.empty())).thenAnswer((_) async => response.body); inside the test in api_provider_test.dart because of the FAQ here about this error, but I couldn't make it work.

Here's the error:

package:http/src/client.dart 62:20                            MockHttpClient.post
package:stock_mobile/data/providers/api_provider.dart 17:45  ApiProvider.login
test\unit\api_provider_test.dart 34:32                             main.<fn>.<fn>.<fn>.<fn>
package:mocktail/src/mocktail.dart 211:8                      when.<fn>
test\unit\api_provider_test.dart 34:13                             main.<fn>.<fn>.<fn>
test\unit\api_provider_test.dart 28:52                             main.<fn>.<fn>.<fn>
===== asynchronous gap ===========================
dart:async                                                    _completeOnAsyncError
package:stock_mobile/data/providers/api_provider.dart        ApiProvider.login
test\unit\api_provider_test.dart 34:32                             main.<fn>.<fn>.<fn>.<fn>
package:mocktail/src/mocktail.dart 211:8                      when.<fn>
test\unit\api_provider_test.dart 34:13                             main.<fn>.<fn>.<fn>
test\unit\api_provider_test.dart 28:52                             main.<fn>.<fn>.<fn>
type 'Future<String>' is not a subtype of type 'Future<Response>'
package:http/src/client.dart 62:20                            MockHttpClient.post
package:stock_mobile/data/providers/api_provider.dart 17:45  ApiProvider.login
test\unit\api_provider_test.dart 36:42                             main.<fn>.<fn>.<fn>
test\unit\api_provider_test.dart 28:52                             main.<fn>.<fn>.<fn>

type 'Null' is not a subtype of type 'Future<Response>'

Thanks in advance...

CodePudding user response:

I think you are missing your named argument when mocking HttpClient method.

Replace when(() => httpClient.post(any())).thenAnswer((_) async => response); with

when(() => httpClient.post(any(), body: any(named: "body")))
            .thenAnswer((_) async => response);

This should now match your method call properly.

  • Related