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:
Good code everyone!