Тестирование виджетов во Flutter: написание независимых, читаемых и быстрых тестов
13 января 2024 г.Во Flutter есть 3 типа тестов:
- Юнит-тесты — обычные модульные тесты, в которых мы пишем тесты для наших функций, методов и классов.
- Тестирование виджетов — мы пишем тесты для наших виджетов и проверяем, совпадают ли они визуально, также можно проверить событие, например клик.
- Интеграционные тесты — как правило, все приложение тестируется и запускается на реальных устройствах или в эмуляторе. ол>
- независимый;
- не следует создавать виджеты;
- быть простым, читабельным и быстрым;
- find.text() — ищет текст;
- find.byKey() — ищет виджет по ключу;
- find.byType() — ищет виджет по типу;
- find.byIcon() — ищет виджет типа Icon;
- find.byWidgetPredicate() — ищет виджет по предикату;
- findsOneWidget — сравнивает, что
Finder
находит только один виджет; - findsWidgets — сравнивает, что
Finder
находит хотя бы один виджет; - isSameColorAs(Color color) — сравнивает, что объект имеет определенный цвет;
- findsNothing — сравнивает, что
Finder
не находит виджет; - isNotNull — сравнивает, что объект не имеет значения NULL;
Из перечисленных тестов разберем тесты Виджета. Цель состоит в том, чтобы протестировать виджет, поскольку в Flutter все является виджетами.
Тесты должны быть:
Для тестовых виджетов метод testWidgets
представлен описанием основных параметров, где можно написать описание в строковом формате, а следующий класс параметров WidgetTester
— это класс, который программно взаимодействует с виджетами и тестовой средой.
testWidgets('Test description', (WidgetTester widgetTester) async {
//...
});
Возьмем, к примеру, приведенный ниже код с полем ввода и кнопкой «Войти»:
class SignInScreen extends StatefulWidget {
const SignInScreen({super.key});
@override
State<StatefulWidget> createState() => _SignInScreenState();
}
class _SignInScreenState extends State<SignInScreen> {
final TextEditingController _textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Check email'),),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: _textEditingController,
key: const ValueKey('email_field'),
decoration: const InputDecoration(hintText: 'Enter e-mail'),
),
const SizedBox(height: 24,),
ElevatedButton(onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => const SuccessScreen()));
}, child: const Text('Sing In'))
],
),
),
);
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Widget test',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const SignInScreen(),
);
}
}
И давайте напишем тест виджета:
void main() {
testWidgets('Widget test', (WidgetTester widgetTester) async {
await widgetTester.pumpWidget(const MaterialApp(home: SignInScreen(),));
Finder title = find.text('Check email');
expect(title, findsOneWidget);
});
testWidgets('Test input field', (WidgetTester widgetTester) async {
await widgetTester.pumpWidget(const MaterialApp(home: SignInScreen(),));
Finder emailTextField = find.byKey(const ValueKey('email_field'));
expect(emailTextField, findsOneWidget);
});
testWidgets('Test sign in button', (WidgetTester widgetTester) async {
await widgetTester.pumpWidget(const MaterialApp(home: SignInScreen(),));
Finder signInButton = find.byType(ElevatedButton);
expect(signInButton, findsOneWidget);
});
}
Метод pumpWidget
визуализирует переданный виджет. Далее с помощью Finder
ищем нужный нам виджет. Вы можете искать по-разному и использовать разные средства поиска. Вот наиболее распространенные из них (их гораздо больше). Вы также можете легко написать свой искатель
.
В приведенном выше примере я использую три метода для заголовка, используя текст find.text('Проверить электронную почту')
, для поля ввода, используя ключ find.byKey(const ValueKey('email_field'))
, а для кнопки - тип find.byType( ElevatedButton)
.
Остается только сравнить полученный результат с заданными искателями с помощью класса Matcher
. Их тоже очень много написано практически на каждый случай жизни. Но вы легко можете написать свой собственный.
Ниже приведены наиболее, на мой взгляд, используемые:
Когда мы запускаем тест и возникает ошибка, мы получаем следующий результат:
Здесь я намеренно пропустил букву, чтобы показать ошибку.
Если тест пройден успешно, мы получим следующий результат:
Спасибо за внимание!
Оригинал