Flutter Basics for Beginners (Part IX)

Flutter allows you to write simple and straightforward tests for different parts of your application.





Today we will try to write several unit tests that are used to test classes, methods, and individual functions.





We will also try to use a library Mockito



that allows you to create fake implementations.





Well, let's start testing!





Our plan
  • Part 1  - introduction to development, first appendix, concept of state;





  • Part 2  - pubspec.yaml file and using flutter on the command line;





  • Part 3  - BottomNavigationBar and Navigator;





  • Part 4  - MVC. We will use this particular pattern as one of the simplest;





  • Part 5  - http package. Creation of the Repository class, first requests, listing of posts;





  • Part 6  - working with forms, text boxes and creating a post.





  • Part 7  - working with pictures, displaying pictures in the form of a grid, receiving pictures from the network, adding your own to the application;





  • Part 8 - creating your own theme, adding custom fonts and animations;





  • Part 9 (current article) - a little about testing;





Adding the required dependencies

We need two additional packages mockito



and build_runner



, therefore, add them:





#   
#     
dev_dependencies:
  flutter_test:
    sdk: flutter
  mockito: ^5.0.10
  build_runner: ^2.0.4
      
      



Now we can start testing





Writing the first test

There will be a small class as a testing object Stack



:





class Stack<T> {
  final stack = <T>[];
  
  void push(T t) {
    stack.add(t);
  }
  
  T? pop() {
    if (isEmpty) {
      return null;
    }
    return stack.removeLast();
  }
  
  bool get isEmpty => stack.isEmpty; 
}

      
      



Please note: the class Stack



is generic.





There is a test,



test folder in the root directory of our project.







Let's create a new file in it stack_test.dart



:





import 'package:flutter_test/flutter_test.dart';
import 'package:json_placeholder_app/helpers/stack.dart';

void main() {
  //  
  group("Stack", () {
    //     
    test("Stack should be empty", () {
      // expect    
      //     
      //    ,   
      expect(Stack().isEmpty, true);
    });
    test("Stack shouldn't be empty", () {
      final stack = Stack<int>();
      stack.push(5);
      expect(stack.isEmpty, false);
    });
    test("Stack should be popped", () {
      final stack = Stack<int>();
      stack.push(5);
      expect(stack.pop(), 5);
    });
    test("Stack should be work correctly", () {
      final stack = Stack<int>();
      stack.push(1);
      stack.push(2);
      stack.push(5);
      expect(stack.pop(), 5);
      expect(stack.pop(), 2);
      expect(stack.isEmpty, false);
    });
  });
}
      
      



Pretty simple! Is not it?





In fact, this is one of the types of testing called unit.





Flutter also supports:





  • Widget testing





  • Integration testing





In this article, we will only cover unit testing.





Let's run our tests with the command flutter test test/stack_test.dart:







Successfully!





Testing post retrieval

First, let's modify the method fetchPosts



:





Future<PostList> fetchPosts({http.Client? client}) async {
  //   URL,  
  //    
  final url = Uri.parse("$SERVER/posts");
  //  GET 
  final response =  (client == null) ? await http.get(url) : await client.get(url);
  //   
  if (response.statusCode == 200) {
    //      
    // json.decode  
    return PostList.fromJson(json.decode(response.body));
  } else {
    //     
    throw Exception("failed request");
  }
}
      
      



Now let's move on to writing the test itself.





We will use mockito



to create fake http.Client'



a





Let's create a file post_test.dart



in the folder tests



:





import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:json_placeholder_app/data/repository.dart';
import 'package:json_placeholder_app/models/post.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';

//    
import 'post_test.mocks.dart';

//  mockito
@GenerateMocks([http.Client])
void main() {
  //   
  final repo = Repository();
  group("fetchPosts", () {
      test('returns posts if the http call completes successfully', () async {
        //   
        final client = MockClient();

        //   
        when(client.get(Uri.parse('https://jsonplaceholder.typicode.com/posts')))
            .thenAnswer((_) async => http.Response('[{"userId": 1, "id": 2, "title": "Title", "content": "Content"}]', 200));

        //    fetchPosts
        //   
        final postList = await repo.fetchPosts(client: client);
        expect(postList, isA<PostList>());
        expect(postList.posts.length, 1);
        expect(postList.posts.first.title, "Title");
      });

      test('throws an exception if the http call completes with an error', () {
        final client = MockClient();

        //  
        when(client.get(Uri.parse('https://jsonplaceholder.typicode.com/posts')))
            .thenAnswer((_) async => http.Response('Not Found', 404));

        //   
        expect(repo.fetchPosts(client: client), throwsException);
      });
  });
}
      
      



Before starting the test, you need to generate a post_test.mocks.dart



file:





flutter pub run build_runner build
      
      



After that, we run our tests with the command flutter test test/post_test.dart



:





Voila!





Conclusion

We have covered one of the simplest and most well-known types of testing - unit (unit).





As already noted, Flutter allows you to test widgets separately, as well as conduct full testing using integration tests.





Useful links:





  • Github source code





  • An introduction to unit testing





  • Mock dependencies using Mockito





  • Testing Flutter apps





Good code everyone!








All Articles