Flutter: Testing Retrofit Using Mockito

Mario Gunawan
Flutter Tips
Published in
3 min readOct 25, 2022

Let’s Mock A Simple Retrofit Application Using Mockito!

Probably, if you are here, you already knows what you’re looking for; so let’s jump to the example. Download the sample Dart App here. If you are using flutter, don’t worry, this concept is applicable to both dart and flutter.

Read the readme to setup the app, then continue to the steps below

Add a new dev dependency in pubspec.yaml:

...
dev_dependencies:
mockito: ^5.3.2
...

In the test folder, create a new folder called “service”. In that folder create a new file named “pokemon_service_test.dart”. Your folder structure should look like this

/test
/service
pokemon_service_test.dart

In “pokemon_service_test.dart”, add those lines:

import 'package:mockito/annotations.dart';
import 'package:poke_dart/service/pokemon_service.dart';
import 'pokemon_service_test.mocks.dart';@GenerateMocks([PokemonService])
void main() {}

Then run flutter pub run build_runner build . This will generate the “pokemon_service_test.mocks.dart” file and fill it with generated code needed to mock PokemonService class.

Now populate the main function with our test:

@GenerateMocks([PokemonService])
void main() {
group("#fetchPokemon", () {
late PokemonService service; setUp(() {
service = MockPokemonService(); // #1
});
test('Fetch Pokemon Successfull Call', () async { final randomListOfPokemon = List.generate(10, (_) =>
generateRandomPokemon());
when(service.fetchPokemon()).thenAnswer( // #2
(realInvocation) async =>
FetchPokemonResponse(
count: 15,
results: randomListOfPokemon));
final expected = FetchPokemonResponse(
count: 15,
results: randomListOfPokemon);
expect(await service.fetchPokemon(), expected);
});
});
}
final random = Random();Pokemon generateRandomPokemon() {
final id = random.nextInt(100);
return Pokemon(
name: "Pokemon #$id",
url: "https://pokeapi.co/api/v2/pokemon/$id"
);
}

Simply, this code will use the mock-able pokemon service class, called “MockPokemonService” (#1). Then, it will answer a certain way when “fetchPokemon” is called (#2). It then compares the result with the expected result.

You can now test it by running dart test . But, it will show you an error even though the expected and awaited object is the same. What happened?

This has something to do with hashing classes. Since the two compared object have different memory addresses, it will not be equal. Thus, one way to resolve this problem is by overriding the == method. If you hate having more libraries and prefer this approach, do create a getter for hashCode too.

What I recommend is using Equatable package to determine equality in dart. Add this to your pubspec.yaml

...
dev_dependencies:
equatable: ^2.0.5
...

Change pokemon.dart and fetch_pokemon_response.dart class signature and override the get props method

// pokemon.dartimport 'package:equatable/equatable.dart';
...
class Pokemon extends Equatable {
...
@override
List<Object?> get props => [name, url];
}
// fetch_pokemon_response.dartimport 'package:equatable/equatable.dart';
...
class FetchPokemonResponse extends Equatable {
...
@override
List<Object?> get props => [results, count, next, previous];
}

What get props does is it tells equatable which properties in our class we want to consider when calculating equality. For example, we can omit count from the FetchPokemonResponse.get props so that if we have two objects with same everything except count, it will still be equal.

When we run dart test again, all test will pass!

That’s it folks, hope this helps!

P.S. As you might have guessed, I’m new in the testing world, so any feedback would be appreciated!

Further reading:

--

--

Mario Gunawan
Flutter Tips

I'm a passionate mobile / web developer. Writing articles about software development, mainly about flutter and react.