How to Write TestCases For API Calls in Flutter?
Last Updated : 16 Oct, 2021
Here we are going to a built app that calls an API and write test cases for it before we dive into it let’s go through some basic concepts.
Software testing is a process in which we test code to ensure that it produces the excepted results at any given instance.
Flutter tests consist of:
- Unit test - test for methods, functions, or class
- Widget test - test for a single widget
- Integration test - test for the large part of or the entire application
As we are going to test a function that calls the API we’ll be doing unit testing. Let’s create the app. You can create the app using the flutter create command or use the IDE of your choice. In the app, we'll use the Numbers API which will give random trivia about numbers, and then will test the function that makes the API call. We are assuming you have some sort of experience with flutter app development.
First, we’ll add the http dependency in the pubspec.yaml file and pub get the dependencies.
XML name: flutter_unit_test description: A new Flutter project. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 environment: sdk: ">=2.12.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter http: 0.13.4 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^1.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages
Now let's create the app. You can remove all the contents of the main.dart file in the lib folder and remove the file in the test folder. Now we'll build the app in the main.dart file.
Dart import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp( MaterialApp( home: Scaffold( appBar: AppBar( title: const Text( 'GeeksForGeeks', ), backgroundColor: Colors.green, ), body: const MyApp(), ), ), ); } class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return FutureBuilder( future: getNumberTrivia(), builder: (BuildContext context, AsyncSnapshot<String> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator( color: Colors.green, ), ); } else if (snapshot.connectionState == ConnectionState.done) { return Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Text( snapshot.data.toString(), ), ), ); } else { return const Center( child: Text( 'Error Occurred', ), ); } }); } } Future<String> getNumberTrivia() async { Uri numberAPIURL = Uri.parse('http://numbersapi.com/random/trivia?json'); final response = await http.get(numberAPIURL); if (response.statusCode == 200) { final Map triviaJSON = jsonDecode(response.body); return triviaJSON['text']; } else { return 'Failed to fetch number trivia'; } }
Run the app using the flutter run command or run button in your IDE.
In order to write a test, we need to understand the method to be tested. Here we have a function named getNumberTrivia that calls an API that returns a JSON response of number trivia upon success otherwise it returns an error message.
Now we can write two test cases first to test whether the successful API response returns a text containing the number trivia and second when the API call fails it returns an error message.
Before we start the test we need to understand that we should not make HTTP requests in the test. It's not recommended. Instead, we must use mocking or stubs. Luckily the HTTP package provides testing.dart file for us to use.
It is recommended that we create a folder called test at the root of the project and write our tests in that. It is already present in our project when we created it. Make sure that you have flutter_test in your dev dependencies and http in the dependencies section of your pubspec.yaml file.
Before we test the function we should make the http dependency as a parameter to the function it will help us in the mocking and stubs part of the test.
Dart Future<String> getNumberTrivia(http.Client http) async { Uri numberAPIURL = Uri.parse('http://numbersapi.com/random/trivia?json'); final response = await http.get(numberAPIURL); if (response.statusCode == 200) { final Map triviaJSON = jsonDecode(response.body); return triviaJSON['text']; } else { return 'Failed to fetch number trivia'; } }
Dart class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return FutureBuilder( future: getNumberTrivia(http.Client()), builder: (BuildContext context, AsyncSnapshot<String> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator( color: Colors.green, ), ); } else if (snapshot.connectionState == ConnectionState.done) { return Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Text( snapshot.data.toString(), ), ), ); } else { return const Center( child: Text( 'Error Occurred', ), ); } }); } }
Create a dart file you can name it as get_number_trivia_unit_test.dart.Make sure that you put _test at the end of the file name this helps flutter understand the files for the test while using the flutter test command.
Some of the functions to know for the flutter test. These functions come from the flutter_test package.
- group(description,body); You can group test cases related to a particular function using the group function. You can write the description of the test in the description parameter and the body contains all the test cases.
- test(description,body); You can write a test case using the test function to which you can provide the description in the parameter and the body will contain the test case itself.
- expect(actual,matcher); You can test the output by using the expect method by providing it the output of the function as an actual parameter and expected output as a matcher.
There is various matcher you can find in the official documentation.
Dart import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; // file which has the getNumberTrivia function import 'package:flutter_unit_test/main.dart'; import 'package:http/http.dart'; import 'package:http/testing.dart'; void main() { group('getNumberTrivia', () { test('returns number trivia string when http response is successful', () async { // Mock the API call to return a json response with http status 200 Ok // final mockHTTPClient = MockClient((request) async { // Create sample response of the HTTP call // final response = { "text": "22834 is the feet above sea level of the highest mountain in the Western Hemisphere, Mount Aconcagua in Argentina.", "number": 22834, "found": true, "type": "trivia" }; return Response(jsonEncode(response), 200); }); // Check whether getNumberTrivia function returns // number trivia which will be a String expect(await getNumberTrivia(mockHTTPClient), isA<String>()); }); test('return error message when http response is unsuccessful', () async { // Mock the API call to return an // empty json response with http status 404 final mockHTTPClient = MockClient((request) async { final response = {}; return Response(jsonEncode(response), 404); }); expect(await getNumberTrivia(mockHTTPClient), 'Failed to fetch number trivia'); }); }); }
In order to run the test enter the following command in the terminal
flutter test
Output:
Similar Reads
How to Integrate Google Maps in Flutter Applications?
We all have seen that Google Maps is used by many applications such as Ola, Uber, Swiggy, and others. We must set up an API project with the Google Maps Platform in order to integrate Google Maps into our Flutter application. In this article, we will look at How to Integrate Google Maps in Flutter A
4 min read
How to Build a Simple Login App with Flutter?
To prevent unauthorized access to personal information, it is a good practice to authenticate users before granting access to websites, mobile applications, and computer applications after they can register and then log in. In this article, we are going to explain how to build a Design Login page us
8 min read
How to Build a Video Calling App in Flutter?
Video Calling has become a necessary feature in most real-time communication applications used around the world. Its primary application is to connect people from all around the world along with other obvious applications. Chat applications like Facebook, WhatsApp, and Instagram all have video calli
4 min read
How to Manage State in Flutter with BLoC Pattern?
State management is an essential part of building any app, and it becomes especially important as your app grows in complexity. In Flutter, there are a number of approaches that you can take to manage state, including using global variables, Inherited Widgets, and more recently, the Provider package
6 min read
Flutter - What is Future and How to Use It?
Future in Flutter refers to an object that represents a value that is not yet available but will be at some point in the future. A Future can be used to represent an asynchronous operation that is being performed, such as fetching data from a web API, reading from a file, or performing a computation
3 min read
How to Add Splash Screen in Flutter App?
We all have heard of Flutter right, it's a cross-platform application development tool. Flutter can be used to make Android, IOS, and Web applications with just one code base (Dart programming language). In this article let's see how we can add a splash screen to our applications. What is Splash Scr
3 min read
How to Import Data From One Page to Another in Flutter?
Flutter is Googleâs Mobile SDK to build native iOS and Android, Desktop (Windows, Linux, macOS), Web apps from a single codebase. When building applications with Flutter everything towards Widgets â the blocks with which the flutter apps are built. They are structural elements that ship with a bunch
5 min read
How to Choose the Right Architecture Pattern For Your Flutter App?
One of the key decisions you'll make when building a Flutter app is selecting the right architecture pattern. The architecture pattern determines how your app's code is organized and how its different components interact with each other. Choosing the right architecture can make it easier to build, t
4 min read
Flutter - Fetching Data From the Internet
In today's world, most applications heavily rely on fetching information from the servers through the internet. In Flutter, such services are provided by the http package. In this article, we will explore this concept. Steps to Implement Data Fetching from the InternetStep 1 : Create a new flutter a
4 min read
How to use Functions of Another File in Flutter?
Flutter is an open-source framework by Google for building beautiful, natively compiled, multi-platform applications from a single codebase. A Single codebase means that only we have to write a single code for Android and IOS and others like Desktop  Application, Web Application. So, Today we are go
2 min read