'Test API calls in Bloc in Flutter

Im first time trying to write Tests for Bloc, Here I face the problem that is :

NoSuchMethodError: The method 'fetchPlayerToLogin' was called on null.
Receiver: null
Tried calling: fetchPlayerToLogin("[email protected]", "test123!")
dart:core                                    Object.noSuchMethod
test/login_bloc_test.dart 31:35              main.<fn>.<fn>
package:bloc_test/src/bloc_test.dart 160:26  runBlocTest.<fn>
package:bloc_test/src/bloc_test.dart 158:5   runBlocTest.<fn>
dart:async                                   runZoned
package:bloc_test/src/bloc_test.dart 157:9   runBlocTest
package:bloc_test/src/bloc_test.dart 127:11  blocTest.<fn>
package:bloc_test/src/bloc_test.dart 126:26  blocTest.<fn>
===== asynchronous gap ===========================
dart:async                                   _completeOnAsyncError
package:bloc_test/src/bloc_test.dart         runBlocTest.<fn>
package:bloc_test/src/bloc_test.dart 158:5   runBlocTest.<fn>
dart:async                                   runZoned
package:bloc_test/src/bloc_test.dart 157:9   runBlocTest
package:bloc_test/src/bloc_test.dart 127:11  blocTest.<fn>
package:bloc_test/src/bloc_test.dart 126:26  blocTest.<fn>

but user exists in database, do you know where might be problem ?

This is my bloc test

class MockPlayerRepository extends Mock implements PlayerRepository {}

void main() {
  MockPlayerRepository mockPlayerRepository;

  setUp() {
    mockPlayerRepository = MockPlayerRepository();
  }

    blocTest(
      'Login Button Pressed',
      build: () {
        when(mockPlayerRepository.fetchPlayerToLogin(
                '[email protected]', 'test123!'))
            .thenAnswer((_) async => player);
        return LoginBloc(repository: mockPlayerRepository);
      },
      act: (bloc) => bloc.add(const LoginEvent.loginButton()),
      expect: [
        LoginState(
            email: EmailAddress('[email protected]'),
            password: Password('test123!'),
            isLoading: false),
        LoginState(
            email: EmailAddress('[email protected]'),
            password: Password('test123!'),
            isLoading: true),
        LoginState(
            email: EmailAddress('[email protected]'),
            password: Password('test123!'),
            isLoading: false),
      ],
    );
  });
}

and my bloc is

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final PlayerRepository repository;
  // ignore: sort_constructors_first
  LoginBloc({@required this.repository})
      : assert(repository != null),
        super(LoginState.initial());

  @override
  Stream<LoginState> mapEventToState(
    LoginEvent event,
  ) async* {
    yield* event.map(emailChanged: (e) async* {
      yield state.copyWith(
        email: EmailAddress(e.email),
      );
    }, passwordChanged: (e) async* {
      yield state.copyWith(
        password: Password(e.password),
      );
    }, loginButton: (e) async* {
      yield state.copyWith(isLoading: true);
      if (state.email.isValid() && state.password.isValid()) {
        final String email = unpack(state.email.value.toIterable().toString());
        final String password =
            unpack(state.password.value.toIterable().toString());

        final Player player =
            await repository.fetchPlayerToLogin(email, password);

        yield state.copyWith(
          player: player,
          isLoading: false,
        );
      }
    });
  }
}

Checked API call with postman works perfectly, the function itself is

class PlayerRepository extends PlayerApiProvider {
  // fetchPlayerToLogin function required to return player if login and password are correct and null if any error occurs
  Future<Player> fetchPlayerToLogin(String email, String password) async =>
      await login(email, password);
}





class PlayerApiProvider {
  //Function for user to Login
  Future<Player> login(String email, String password) async {
    try {
      final http.Response response = await http.patch(
        '$octollengeURL/login',
        headers: <String, String>{
          'Content-Type': 'application/json',
          'Accept-Encoding': 'application/json',
        },
        body: jsonEncode(<String, String>{
          'email': email,
          'password': password,
        }),
      );

      if (response.statusCode == 200) {
        return Player.fromJson(response.body);
      } else if (response.statusCode == 400) {
        showSnack('User is not registered', errColor, Colors.white);
        return null;
      } else if (response.statusCode == 403) {
        showSnack('Password is incorrect', errColor, Colors.white);
        return null;
      } else {
        showSnack('Server error with status code : ${response.statusCode}',
            errColor, Colors.white);
        return null;
      }
    } on SocketException {
      showSnack('No internet Connection', errColor, Colors.white);
      return null;
    } on HttpException {
      showSnack(
          'Think we have troubles on server side', errColor, Colors.white);
      return null;
    } on FormatException {
      showSnack(
          'You got bad response format, try again', errColor, Colors.white);
      return null;
    } catch (e) {
      logger.e(e.toString());
      showSnack(
          'Think we have troubles on server side', errColor, Colors.white);
      return null;
    }
  }
}

Used to change the input of function to 'any' keyword but still have the same issue if you need more information I can provide



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source