Привет! Сегодня я хотел бы поделиться несколькими советами о том, как писать тесты на Flutter. Некоторые говорят, что написание тестов замедляет вас, но это неправда, если вы знаете, как их писать эффективно. Есть несколько хороших практик, как этого добиться практически на каждом языке и во всех фреймворках. В этой статье я покажу вам некоторые из них во Flutter.

Если вы хотите сначала изучить основы тестирования Flutter, я рекомендую вам посетить сайт Flutter. Вы можете найти там объяснение модульных тестов, тестов виджетов и интеграций. В противном случае давайте начнем с сегодняшних советов!

Следуй за «дано-когда-тогда»

Вы знакомы с подходом Дано-Когда-Тогда? Это стиль формулирования ваших тестов. Используя эту идею, вы начинаете тест с описания начального состояния (например, данный пользователь вошел в систему), а затем описываете, что должно произойти (например, когда пользователь нажимает кнопку ), и, наконец, вы описываете ожидаемое состояние или результат (например, Затем пользователь видит сообщение, выполнившее вход в систему). Таким образом вы сможете четко разделить условия, действия и результаты и понять, какова цель каждого теста.

Более того, вы также можете использовать эту концепцию в названии теста! Вот как это может выглядеть во Flutter:

testWidgets(
    'GIVEN user is logged in '
    'WHEN user taps on a button '
    'THEN info is shown', (tester) async {
  
  // given
  when(user.isLoggedIn).thenReturn(true);
  
  // when
  await tester.pumpWidget(Home());
  await tester.tap(find.byType(FlatButton));
  await tester.pump();
  
  // then
  expect(find.text('I\'m logged in!'), findsOneWidget);
});

Примечание. Если вы не знаете, что означает when(…).thenReturn(…), прочтите, чтобы узнать о mockito. Это необходимо для тестирования!

Используйте Mockito

Если вы еще не знаете mockito, он станет вашим лучшим другом в тестировании. Mockito - это библиотека, которая позволяет имитировать поведение классов. Зачем вам это может понадобиться? Самый простой вариант использования - это, конечно, все, что требует времени и ресурсов, например вызовы API, операции с базой данных, загрузка ресурсов из сети и т. Д. Эти службы могут занять некоторое время, и вы не всегда можете предсказать их результат, поэтому вы действительно не должны Не хочу их в ваших тестах. Представьте, что вы запускаете тест, который случайно не проходит из-за плохого подключения к Интернету!

Вот где mockito становится очень полезным. Вы можете использовать его, чтобы имитировать поведение любого (!) Класса, которое вы хотите, и вернуть ожидаемое поведение. Например:

when(apiClient.fetchKittyNames()).thenReturn(['Lilly', 'Bella','Coco']);
when(databaseManager.saveProduct()).thenReturn(true);
when(resourceProvider.getImage()).thenThrow(Exception());

Таким образом, вы можете проверить все возможности в своих тестах с полным контролем над внешними зависимостями. Довольно круто, правда?

Однако это не только для длительных операций. Вы можете использовать Mockito для всех ваших зависимостей. Давайте посмотрим на предыдущий пример, когда пользователь вошел в систему. Если мы хотим протестировать различные варианты поведения в зависимости от состояния пользователя, мы должны передать User mock Home виджету:

testWidgets(
    'GIVEN user is logged in '
    'WHEN user taps on a button '
    'THEN info is shown', (tester) async {
  
  // given
  final user = UserMock();
  ...  
  // when
  await tester.pumpWidget(MaterialApp(home: Home(user: user)));
  ...
});

Где UserMock - новый класс, созданный вне теста с mockito:

class UserMock extends Mock implements User {}

Таким образом, мы можем контролировать, вошел ли пользователь в систему или нет, и проверять это в нашем тесте:

testWidgets(
    'GIVEN user is logged in '
    'WHEN user taps on a button '
    'THEN info is shown', (tester) async {
  
  // given
  final user = UserMock();
  when(user.isLoggedIn).thenReturn(true);
  
  // when
  await tester.pumpWidget(MaterialApp(home: Home(user: user)));
  await tester.tap(find.byType(FlatButton));
  await tester.pump();
  
  // then
  expect(find.text('I\'m logged in!'), findsOneWidget);
});

Вы можете проверить полный исходный код на моем GitHub:

На сегодня все! Я надеюсь, что этот пост прояснил для вас тему тестирования Flutter. Если вам все еще нужна дополнительная информация, я рекомендую вам глубже погрузиться в Документацию по Flutter, где вы можете найти множество полезных статей и руководств. Спасибо за прочтение! 👋

Https://www.twitter.com/FlutterComm