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.