Reputation: 1002
I want to test a remote server request method but I can not figure out why I get : No matching calls. All calls: MockClient.send(GET https://exampleDomain.test.com/send_email).
I've searched the stack overflow and someone used equatable
package to compare objects but I don't know how to implement this package or equality for MockRequest
object which implements http.Request
.
Here is my method:
@override
Future<void> sendEmail(String email) async {
if (!EmailValidator.validate(email)) throw InvalidEmailFormatException();
final requestUrl = baseUri.replace(path: '/account/send_email');
final request = http.Request(RequestMethod.get.method, requestUrl);
request.headers.clear();
request.headers.addAll({"Content-type": "text/plain"});
request.body = '{"email":"$email"}';
try {
final response = await _client.send(request);
if (response.statusCode != 200) {
throw HttpException(
'Response statuse code = ${response.statusCode}, Reason phrase = ${response.reasonPhrase}',
uri: requestUrl);
}
final responseBodyString = await response.stream.bytesToString();
final reponseJson =
jsonDecode(responseBodyString) as Map<String, dynamic>;
final code = reponseJson['code'];
if (code != 200) {
throw ServerException(code, uri: requestUrl);
}
} on SocketException {
rethrow;
} on FormatException {
rethrow;
}
}
and here is my unit test:
class MockClient extends Mock implements http.Client {}
class MockResponse extends Mock implements http.StreamedResponse {}
class MockRequest extends Mock with EquatableMixin implements http.Request {}
...
test('make correct http request', () async {
final uri = baseUri.replace(path: 'account/send_email');
final response = MockResponse();
when(
() => response.statusCode,
).thenReturn(200);
when(
() => response.stream,
).thenAnswer(
(_) => http.ByteStream.fromBytes('OK'.codeUnits),
);
final request = MockRequest();
when(
() => request.method,
).thenReturn('GET');
when(
() => request.body,
).thenReturn('{"email":"$validEmail"}');
when(
() => request.headers,
).thenReturn({
'Content-Type': 'text/plain',
});
when(
() => request.url,
).thenReturn(uri);
when(() => client.send(any())).thenAnswer((_) async => response);
try {
await sut.sendEmail(validEmail);
} catch (_) {}
verify(() => client.send(request)).called(1);
});
Upvotes: 0
Views: 634
Reputation: 1002
Using meta
package you should inject Mockrequest to the constructor with @visibleForTesting annotation.
final htt.Request? _request;
class Api{
Api(@visibleForTesting http.Request? request): _request = request;
@override
Future<void> sendEmail(String email) async {
...
final request = _request ?? http.Request(RequestMethod.get.method, requestUrl);
...
}
}
Then in the test unit use MockRequest to inject in Api class.
test('calls the correct endpoint', () async {
final email = '[email protected]';
when(
() => mockRequest.url,
).thenReturn(baseUri.replace(path: '/account/send_email'));
when(
() => mockRequest.method,
).thenReturn(RequestMethod.post);
when(
() => mockRequest.headers,
).thenReturn({'Content-Type': 'text/plain'});
when(
() => mockRequest.body,
).thenReturn('{"email": "$email"}');
try {
await sut.sendEmail(email);
} catch (e) {}
verify(
() => client.send(mockRequest),
).called(1);
});
Upvotes: 0