Основы Flutter для начинающих (Часть IX)

    Flutter позволяет вам писать простые и понятные тесты для разных частей приложения.

    Сегодня мы попробуем написать несколько unit тестов, которые используются для тестирования классов, методов и отдельных функций.

    Также мы попробуем использовать библиотеку Mockito, которая позволяет создавать фейковые реализации.

    Ну что ж, приступаем к тестированию!

    Наш план
    • Часть 1 - введение в разработку, первое приложение, понятие состояния;

    • Часть 2 - файл pubspec.yaml и использование flutter в командной строке;

    • Часть 3 - BottomNavigationBar и Navigator;

    • Часть 4 - MVC. Мы будем использовать именно этот паттерн, как один из самых простых;

    • Часть 5 - http пакет. Создание Repository класса, первые запросы, вывод списка постов;

    • Часть 6 - работа с формами, текстовые поля и создание поста.

    • Часть 7 - работа с картинками, вывод картинок в виде сетки, получение картинок из сети, добавление своих в приложение;

    • Часть 8 - создание своей темы, добавление кастомных шрифтов и анимации;

    • Часть 9 (текущая статья) - немного о тестировании;

    Добавления необходимых зависимостей

    Нам понадобиться два дополнительных пакета mockito и build_runner, поэтому добавим их:

    # зависимости для разработки
    # в данном случае подключено тестирование
    dev_dependencies:
      flutter_test:
        sdk: flutter
      mockito: ^5.0.10
      build_runner: ^2.0.4

    Теперь мы можем приступать к тестированию

    Пишем первый тест

    В качестве объекта тестирования будет небольшой класс 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; 
    }
    

    Обратите внимание: класс Stack является обобщенным.

    В корневой директории нашего проекта есть папка test, которая предназначена для тестов.

    Создадим в ней новый файл 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);
        });
      });
    }

    Довольно просто! Не правда ли?

    На самом деле, это один из типов тестирования, который называется unit (модульное).

    Также Flutter поддерживает:

    • Widget тестирование

    • Интеграционное тестирование

    В данной статье мы рассмотрим только unit тестирование.

    Давайте выполним наши тесты командой flutter test test/stack_test.dart:

    Успешно!

    Тестируем получение постов

    Сначала видоизменим метод 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");
      }
    }

    Теперь переходим к написанию самого теста.

    Мы будем использовать mockito для создания фейкового http.Client'а

    Создадим файл post_test.dart в папке 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);
          });
      });
    }

    Перед запуском теста необходимо сгенерировать post_test.mocks.dart файл:

    flutter pub run build_runner build

    После этого выполняем наши тесты командой flutter test test/post_test.dart:

    Вуаля!

    Заключение

    Мы разобрали один из самых простых и известных типов тестирования - unit (модульное).

    Как уже было отмечено, Flutter позволяет отдельно тестировать виджеты, а также проводить полноценное тестирование с применением интеграционных тестов.

    Полезные ссылки:

    Всем хорошего кода!

    Средняя зарплата в IT

    120 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 8 887 анкет, за 1-ое пол. 2021 года Узнать свою зарплату
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое