CodeChai
Published in

CodeChai

Mocking HTTP request in Flutter

Hi Folks! I am back with a brand new article and this time its something different from development.

Testing time!! 😃

In this article I won’t be covering each and every part of testing in Flutter. But rather a very important topic in the world of testing mobile apps. “Mocking HTTP request!”

Now you must be having many questions regarding mocking. Let me tackle those one by one.

What mocking really means ?

If you check the dictionary it says “make a replica or imitation of something.”

What is the role of mocking in testing mobile apps?

Mocking is primarily used in unit testing. An object under test may have dependencies on other (complex) objects. To isolate the behavior of the object you want to replace the other objects by mocks that simulate the behavior of the real objects. This is useful if the real objects are impractical to incorporate into the unit test.

In short, mocking is creating objects that simulate the behaviour of real objects.(source: stackoverflow)

Can you tell me a real world scenario where mocking plays a vital role?

This is the best answer you can ever find in the internet.

Note: Please read the above linked answer carefully before you read any further.

Hope those Q&A cleared most of the clouds around the concept of mocking.

Let’s jump back to the goal for which we gathered here. Mocking HTTP request in Flutter.

Let me go step by step on how we can achieve this in Flutter. First we will setup all the files and directories we need. So please follow the steps as mentioned. I will explain the important parts as and when needed:

  1. Let’s first create a simple Flutter project. You can name the project anything you want, no hard and fast rule on that. Open your project and delete every single code from your main.dart file.
  2. Add the below code in your main.dart file. After pasting the code you must be seeing some errors but don’t sweat, we will be fixing them in a minute:
import 'package:flutter/material.dart';
import 'src/app.dart';
void main(){
runApp(App());
}

3. Create a new package inside the lib directory and name it as ‘src’. Create a file inside the src directory and name it as app.dart. Paste below code inside it.

import 'package:flutter/material.dart';
class App extends StatelessWidget{
@override
Widget build(BuildContext context) {
return
MaterialApp(
home: Scaffold(
body: Container(),
),
);
}
}

4. Create one more package inside the src directory and name it as ‘resources’. Create a file inside it and name it as api_provider.dart. This file is responsible for holding all the HTTP request the app is making to the server. We are following the famous repository pattern here. Copy and paste below code inside api_provider.dart file.

import 'package:http/http.dart' show Client;
import '../models/item_model.dart';
import 'dart:convert';

class ApiProvider {
Client client = Client();
fetchPosts() async {
final response = await client.get("https://jsonplaceholder.typicode.com/posts/1");
ItemModel itemModel = ItemModel.fromJson(json.decode(response.body));
return itemModel;
}
}

5. As always when it comes to making a HTTP request for a demo. We will be using our old friend jsonplaceholder. We will be hitting the below API to get a JSON response which we will be consuming in our app.

https://jsonplaceholder.typicode.com/posts/1

JSON response:

{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}

As you can see above we have a JSONObject which have 4 key & value pairs.

6. Whenever we talk about JSON in mobile app development. We create a POJO class for it and that’s what we will be doing next. Create a new package under src directory and name it as ‘models’. Inside it create a file and name it as item_model.dart. Copy and paste below code inside the item_model.dart file.

class ItemModel{
int _userId;
int _id;
String _title;
String _body;
ItemModel.fromJson(Map<String,dynamic> parsedJson){
_userId = parsedJson['userId'];
_id = parsedJson['id'];
_title = parsedJson['title'];
_body = parsedJson['body'];
}

String get body => _body;

String get title => _title;

int get id => _id;

int get userId => _userId;

}

ItemModel.fromJson() is a named constructor. You can read about named constructor from here. The constructor takes Map as a parameter. Whenever you decode a JSON in dart it always returns a Map<String, dynamic> type instance. Here String is the key and dynamic is the value in JSON as it can be of any type.

Now this is how your project structure should be looking:

project structure

Now let’s come to the important part of this article. Testing the HTTP request implementation that we have written in our ApiProvider class before we even start integrating it with the UI section.

Note: We won’t be playing with UI in this article.

7. Inside the test directory you will find a file named as widget_test.dart. Delete the file as we will be creating our own. As you know that the network implementation is done inside the api_provider.dart file. We will be only testing the fetchPosts() method inside the file. Create a new file inside the test directory and name it as api_provider_test.dart.

Warning: DON’T MISS THE “_test” in the name of the file or else Flutter will fail to recognise it as a test file.

8. Now let’s open the file do the first thing. Import all the packages we need to complete the test. Here are list of imports we need to do:

import 'package:test/test.dart';
import 'package:http/http.dart';
import 'package:http/testing.dart';
import 'dart:convert';
import 'package:my_test/src/resources/api_provider.dart';

test.dart provides us the standard methods to test our code and http/testing.dart provide us the tools to mock our HTTP request and help us find out if our implementation is working or not.

9. As we know the main point of execution starts from the main() method. So lets create the main() method.

10. Inside the main() method to test any code. We will use the method test() provided by test.dart package. This is how you use the method:

void main(){
test("Testing the network call", (){

});
}

The first parameter is the description of the test we will be conducting. Second parameter, it takes a blank method where we will be writing our mocking code.

11. Inside the blank method we will be creating the object of the ApiProvider class. Now please read this carefully, as you know that we are mocking the HTTP request and not making a real network request, we will be changing the Client() object inside ApiProvider class to the type of MockClient(). MockClient is a special client provided by the http/testing.dart package which will imitate a HTTP request but will never make a real request to the server. You will end up with the below code inside api_provider_test.dart:

void main(){
test("Testing the network call", (){
//setup the test
final
apiProvider = ApiProvider();
apiProvider.client = MockClient((request) {

});
});
}

12. As you know every HTTP call will have a request and response object. Request object is already supplied as a parameter to the MockClient, we have to create the Response() object. This is how we create the Response object:

void main(){
test("Testing the network call", (){
//setup the test
final
apiProvider = ApiProvider();
apiProvider.client = MockClient((request) async {
final mapJson = {'id':123};
return Response(json.encode(mapJson),200);
});
});
}

As you can see the response object is returning a JSON object which is the body of the response. The second parameter is the status code of the response which here it means a successful request.

The last part is we will be checking if the method fetchPosts() inside api_provider.dart file which return a ItemModel object contains the key id with value 123 or not. Here is the last method expect() from the test.dart package which will test our fetchPosts() method output with the output we are expecting i.e id=123:

void main(){
test("Testing the network call", () async{
//setup the test
final
apiProvider = ApiProvider();
apiProvider.client = MockClient((request) async {
final mapJson = {'id':123};
return Response(json.encode(mapJson),200);
});
final item = await apiProvider.fetchPosts();
expect(item.id, 123);
});
}

Now its time to run the test file and check if the test case is passing or not. In your terminal navigate to the project directory and type flutter test. This should be your output This tell us that item.id has the value 123 as we expected and the test case is passed.

Volla! Test case passed 😍

This is what it takes to mock your HTTP request in Flutter. I am ending this long article here. I know you must be tired as well. But its worth reading and getting this far. Thank you everyone for your patience and your eagerness to learn new stuffs. You can connect with me in LinkedIn for any requirements or queries you have. Will be back soon with another article. Peace out.

The Flutter Pub is a medium publication to bring you the latest and amazing resources such as articles, videos, codes, podcasts etc. about this great technology to teach you how to build beautiful apps with it. You can find us on Facebook, Twitter, and Medium or learn more about us here. We’d love to connect! And if you are a writer interested in writing for us, then you can do so through these guidelines.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sagar Suri

Sagar Suri

Google certified Android app developer | Flutter Developer | Computer Vision Engineer | Gamer