Mocking HTTP response with Dart

2019-07-04 03:24发布

问题:

I have been working on a new API wrapper and don't want to be calling the API every time my unit tests run. So as described here, I'm mocking it.

I initially thought there was something wrong with the way I'm mocking it, but it seems the problem is elsewhere.

What I'm trying to accomplish is very simple. When my unit test run, I would like to return a value as if I had gone out to get the information from the external API I'm integrating with.

I initialise my class with http.Client as an optional parameter, so I can pass it in when the unit tests run as such:

SampleClass(String arg1, String arg2, [http.Client httpClient = null]) {
    this._arg1 = arg1;
    this._arg2 = arg2;
    _httpClient = (httpClient == null) ? http.Request : httpClient;
}

Future apiRequest(String resource, [Map<String, String> body]) {
    var url = buildBaseUrl(resource).toString();
    var request = new http.Request('POST', Uri.parse(url));
    request.bodyFields = body;
    return this._httpClient.send(request).then((response) => response.stream.bytesToString().then((value) => value.toString()));
}

In my unit test I have created the following mock class:

class HttpClientMock extends Mock implements http.Client {
  noSuchMethod(i) => super.noSuchMethod(i);
}

class HttpResponseMock extends Mock implements http.Response {
    noSuchMethod(i) => super.noSuchMethod(i);
}

And in my unit test to check the response I'm doing the following:

test("Send SMS errors with wrong account", () {
    var mockHttpClient = new HttpClientMock()
                             ..when(callsTo('send')).alwaysReturn(message401);
    var sample = new SampleClass(_arg1, _arg2, mockHttpClient);
    future = sample.apiRequest(...parameters here...).then((value) => value.toString());
    expect(future.then((value) => JSON.decode(value)), completion(equals(JSON.decode(message401))));
});

So, as you can see, I am trying to make it so calling send returns message401, which is just a JSON string.

This is not happening, since message401 is a string, and because my code tries to use it as a Future, I always get the error:

Top-level uncaught error: Class 'String' has no instance method 'then'.

I totally understand why I'm getting this error, but have no idea about how to go around it.

Any help appreciated.

回答1:

The http package has a testing library with a MockClient already implemented for you.



回答2:

Try

.alwaysReturn(new Future.value(message401));