1. مقدمه
Flutter جعبه ابزار UI گوگل برای ساخت برنامه های زیبا و بومی کامپایل شده برای موبایل، وب و دسکتاپ از یک پایگاه کد واحد است.
در این کد لبه، شما یک برنامه Flutter ساده را ساخته و آزمایش خواهید کرد. این برنامه از بسته ارائه دهنده برای مدیریت وضعیت استفاده می کند.
چیزی که یاد خواهید گرفت
- نحوه ایجاد تست ویجت با استفاده از چارچوب تست ویجت
- نحوه ایجاد یک تست یکپارچه سازی برای آزمایش رابط کاربری و عملکرد برنامه با استفاده از کتابخانه
integration_test
- نحوه تست کلاس های داده (ارائه دهندگان) با کمک تست های واحد
چیزی که خواهی ساخت
در این کد لبه، شما با ساختن یک برنامه کاربردی ساده با لیستی از موارد شروع خواهید کرد. ما کد منبع را برای شما فراهم می کنیم تا بتوانید مستقیماً به آزمایش بروید. این برنامه از عملیات زیر پشتیبانی می کند:
- افزودن موارد به موارد دلخواه
- مشاهده لیست علاقه مندی ها
- حذف موارد از لیست علاقه مندی ها
پس از تکمیل برنامه، تست های زیر را می نویسید:
| GIF برنامه در حال اجرا در اندروید |
دوست دارید از این کد لبه چه چیزی یاد بگیرید؟
2. محیط توسعه Flutter خود را تنظیم کنید
برای تکمیل این آزمایشگاه به دو نرم افزار نیاز دارید - Flutter SDK و یک ویرایشگر .
شما می توانید کدلب را با استفاده از هر یک از این دستگاه ها اجرا کنید:
- یک دستگاه فیزیکی Android یا iOS که به رایانه شما متصل شده و روی حالت Developer تنظیم شده است.
- شبیه ساز iOS (نیاز به نصب ابزار Xcode دارد).
- شبیه ساز اندروید (نیاز به نصب در Android Studio دارد).
- یک مرورگر (Chrome برای اشکال زدایی لازم است).
- به عنوان یک برنامه دسکتاپ Windows ، Linux ، یا macOS . شما باید روی پلتفرمی که قصد استقرار در آن را دارید توسعه دهید. بنابراین، اگر می خواهید یک برنامه دسکتاپ ویندوز توسعه دهید، باید در ویندوز توسعه دهید تا به زنجیره ساخت مناسب دسترسی داشته باشید. الزامات خاص سیستم عامل وجود دارد که به طور مفصل در docs.flutter.dev/desktop پوشش داده شده است.
3. شروع به کار
یک برنامه Flutter جدید ایجاد کنید و وابستگی ها را به روز کنید
این آزمایشگاه کد روی آزمایش یک برنامه موبایل Flutter تمرکز دارد. با استفاده از فایلهای منبعی که کپی و جایگذاری میکنید، به سرعت برنامهای را ایجاد میکنید تا آزمایش شود. سپس بقیه بخش کد روی یادگیری انواع مختلف تست تمرکز می کند.
یک برنامه Flutter با قالب ساده ایجاد کنید، یا با استفاده از دستورالعملهای شروع به کار با اولین برنامه Flutter خود ، یا در خط فرمان به شرح زیر.
$ flutter create --empty testing_app Creating project testing_app... Resolving dependencies in `testing_app`... Downloading packages... Got dependencies in `testing_app`. Wrote 128 files. All done! You can find general documentation for Flutter at: https://docs.flutter.dev/ Detailed API documentation is available at: https://api.flutter.dev/ If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev In order to run your empty application, type: $ cd testing_app $ flutter run Your empty application code is in testing_app/lib/main.dart.
وابستگی های میخانه را در خط فرمان اضافه کنید.
-
provider
برای مدیریت آسان ایالت، -
integration_test
برای تست خودرانی کد فلاتر در دستگاه ها و شبیه سازها، -
flutter_driver
برای یک API پیشرفته برای آزمایش برنامه های Flutter که روی دستگاه ها و شبیه سازهای واقعی اجرا می شوند، -
test
برای ابزار تست عمومی، -
go_router
برای مدیریت ناوبری برنامه.
$ cd testing_app $ flutter pub add provider go_router dev:test 'dev:flutter_driver:{"sdk":"flutter"}' 'dev:integration_test:{"sdk":"flutter"}' Resolving dependencies... Downloading packages... + _fe_analyzer_shared 67.0.0 (68.0.0 available) + analyzer 6.4.1 (6.5.0 available) + args 2.5.0 + convert 3.1.1 + coverage 1.7.2 + crypto 3.0.3 + file 7.0.0 + flutter_driver 0.0.0 from sdk flutter + flutter_web_plugins 0.0.0 from sdk flutter + frontend_server_client 4.0.0 + fuchsia_remote_debug_protocol 0.0.0 from sdk flutter + glob 2.1.2 + go_router 14.0.2 + http_multi_server 3.2.1 + http_parser 4.0.2 + integration_test 0.0.0 from sdk flutter + io 1.0.4 + js 0.7.1 leak_tracker 10.0.4 (10.0.5 available) leak_tracker_flutter_testing 3.0.3 (3.0.5 available) + logging 1.2.0 material_color_utilities 0.8.0 (0.11.1 available) meta 1.12.0 (1.14.0 available) + mime 1.0.5 + nested 1.0.0 + node_preamble 2.0.2 + package_config 2.1.0 + platform 3.1.4 + pool 1.5.1 + process 5.0.2 + provider 6.1.2 + pub_semver 2.1.4 + shelf 1.4.1 + shelf_packages_handler 3.0.2 + shelf_static 1.1.2 + shelf_web_socket 1.0.4 + source_map_stack_trace 2.1.1 + source_maps 0.10.12 + sync_http 0.3.1 + test 1.25.2 (1.25.4 available) test_api 0.7.0 (0.7.1 available) + test_core 0.6.0 (0.6.2 available) + typed_data 1.3.2 + watcher 1.1.0 + web 0.5.1 + web_socket_channel 2.4.5 + webdriver 3.0.3 + webkit_inspection_protocol 1.2.1 + yaml 3.1.2 Changed 44 dependencies! 9 packages have newer versions incompatible with dependency constraints. Try `flutter pub outdated` for more information.
وابستگی های زیر باید به pubspec.yaml شما اضافه می شد:
pubspec.yaml
name: testing_app description: "A new Flutter project." publish_to: 'none' version: 0.1.0 environment: sdk: '>=3.4.0-0 <4.0.0' dependencies: flutter: sdk: flutter go_router: ^14.0.2 provider: ^6.1.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.0 test: ^1.25.2 flutter_driver: sdk: flutter integration_test: sdk: flutter flutter: uses-material-design: true
پروژه را در ویرایشگر کد مورد نظر خود باز کنید و برنامه را اجرا کنید. یا آن را در خط فرمان به صورت زیر اجرا کنید.
$ flutter run
4. برنامه را بسازید
در مرحله بعد، برنامه را می سازید تا بتوانید آن را آزمایش کنید. این برنامه حاوی فایل های زیر است:
-
lib/models/favorites.dart
- کلاس مدل را برای لیست علاقه مندی ها ایجاد می کند -
lib/screens/favorites.dart
- طرح بندی لیست علاقه مندی ها را ایجاد می کند -
lib/screens/home.dart
- لیستی از موارد را ایجاد می کند -
lib/main.dart
- فایل اصلی که برنامه از آنجا شروع می شود
ابتدا مدل Favorites
را در lib/models/favorites.dart
ایجاد کنید
یک دایرکتوری جدید به نام models
در دایرکتوری lib
ایجاد کنید و سپس یک فایل جدید به نام favorites.dart
ایجاد کنید. در آن فایل کد زیر را اضافه کنید:
lib/models/favorites.dart
import 'package:flutter/material.dart';
/// The [Favorites] class holds a list of favorite items saved by the user.
class Favorites extends ChangeNotifier {
final List<int> _favoriteItems = [];
List<int> get items => _favoriteItems;
void add(int itemNo) {
_favoriteItems.add(itemNo);
notifyListeners();
}
void remove(int itemNo) {
_favoriteItems.remove(itemNo);
notifyListeners();
}
}
صفحه Favorites را در lib/screens/favorites.dart
اضافه کنید
یک دایرکتوری جدید به نام screens
در دایرکتوری lib
ایجاد کنید و در آن دایرکتوری یک فایل جدید به نام favorites.dart
ایجاد کنید. در آن فایل کد زیر را اضافه کنید:
lib/screens/favorites.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/favorites.dart';
class FavoritesPage extends StatelessWidget {
const FavoritesPage({super.key});
static String routeName = 'favorites_page';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Favorites'),
),
body: Consumer<Favorites>(
builder: (context, value, child) => ListView.builder(
itemCount: value.items.length,
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (context, index) => FavoriteItemTile(value.items[index]),
),
),
);
}
}
class FavoriteItemTile extends StatelessWidget {
const FavoriteItemTile(this.itemNo, {super.key});
final int itemNo;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
),
title: Text(
'Item $itemNo',
key: Key('favorites_text_$itemNo'),
),
trailing: IconButton(
key: Key('remove_icon_$itemNo'),
icon: const Icon(Icons.close),
onPressed: () {
Provider.of<Favorites>(context, listen: false).remove(itemNo);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Removed from favorites.'),
duration: Duration(seconds: 1),
),
);
},
),
),
);
}
}
صفحه اصلی را در lib/screens/home.dart
اضافه کنید
در دایرکتوری lib/screens
یک فایل جدید دیگر به نام home.dart
ایجاد کنید. در lib/screens/home.dart
کد زیر را اضافه کنید:
lib/screens/home.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import '../models/favorites.dart';
import 'favorites.dart';
class HomePage extends StatelessWidget {
static String routeName = '/';
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Testing Sample'),
actions: <Widget>[
TextButton.icon(
onPressed: () {
context.go('/${FavoritesPage.routeName}');
},
icon: const Icon(Icons.favorite_border),
label: const Text('Favorites'),
),
],
),
body: ListView.builder(
itemCount: 100,
cacheExtent: 20.0,
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (context, index) => ItemTile(index),
),
);
}
}
class ItemTile extends StatelessWidget {
final int itemNo;
const ItemTile(this.itemNo, {super.key});
@override
Widget build(BuildContext context) {
var favoritesList = Provider.of<Favorites>(context);
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
),
title: Text(
'Item $itemNo',
key: Key('text_$itemNo'),
),
trailing: IconButton(
key: Key('icon_$itemNo'),
icon: favoritesList.items.contains(itemNo)
? const Icon(Icons.favorite)
: const Icon(Icons.favorite_border),
onPressed: () {
!favoritesList.items.contains(itemNo)
? favoritesList.add(itemNo)
: favoritesList.remove(itemNo);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(favoritesList.items.contains(itemNo)
? 'Added to favorites.'
: 'Removed from favorites.'),
duration: const Duration(seconds: 1),
),
);
},
),
),
);
}
}
محتویات lib/main.dart
را جایگزین کنید
محتوای lib/main.dart
را با کد زیر جایگزین کنید:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'models/favorites.dart';
import 'screens/favorites.dart';
import 'screens/home.dart';
void main() {
runApp(const TestingApp());
}
final _router = GoRouter(
routes: [
GoRoute(
path: HomePage.routeName,
builder: (context, state) {
return const HomePage();
},
routes: [
GoRoute(
path: FavoritesPage.routeName,
builder: (context, state) {
return const FavoritesPage();
},
),
],
),
],
);
class TestingApp extends StatelessWidget {
const TestingApp({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Favorites>(
create: (context) => Favorites(),
child: MaterialApp.router(
title: 'Testing Sample',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepPurple,
),
useMaterial3: true,
),
routerConfig: _router,
),
);
}
}
این برنامه اکنون کامل است، اما آزمایش نشده است.
برنامه را اجرا کنید. باید شبیه تصویر زیر باشد:
برنامه لیستی از موارد را نشان می دهد. روی نماد قلب در هر ردیف ضربه بزنید تا قلب پر شود و مورد به لیست علاقه مندی ها اضافه شود. دکمه Favorites در AppBar
شما را به صفحه دوم حاوی لیست علاقه مندی ها می برد.
اکنون برنامه برای آزمایش آماده است. در مرحله بعد شروع به آزمایش برنامه خواهید کرد.
5. واحد تست ارائه دهنده
شما با واحد آزمایش مدل favorites
شروع خواهید کرد. آزمون واحد چیست؟ تست واحد تأیید میکند که هر واحد نرمافزار، خواه یک تابع، شی یا ویجت باشد، وظیفه مورد نظر خود را به درستی انجام میدهد.
تمام فایل های آزمایشی در یک برنامه Flutter، به جز تست های یکپارچه سازی، در فهرست راهنمای test
قرار می گیرند.
test/widget_test.dart
را حذف کنید
قبل از شروع آزمایش، فایل widget_test.dart
را حذف کنید. شما فایل های آزمایشی خود را اضافه خواهید کرد.
یک فایل آزمایشی جدید ایجاد کنید
ابتدا، متد add()
در مدل Favorites
آزمایش میکنید تا بررسی کنید که آیتم جدیدی به لیست اضافه میشود و اینکه لیست تغییر را منعکس میکند. طبق قرارداد، ساختار دایرکتوری در دایرکتوری test
شبیه به آن است که در دایرکتوری lib
و فایل های Dart هم نامی با _test
ضمیمه شده دارند.
یک دایرکتوری models
در دایرکتوری test
ایجاد کنید. در این فهرست جدید، یک فایل favorites_test.dart
با محتوای زیر ایجاد کنید:
test/models/favorites_test.dart
import 'package:test/test.dart';
import 'package:testing_app/models/favorites.dart';
void main() {
group('Testing App Provider', () {
var favorites = Favorites();
test('A new item should be added', () {
var number = 35;
favorites.add(number);
expect(favorites.items.contains(number), true);
});
});
}
چارچوب تست فلاتر به شما امکان می دهد تست های مشابه مرتبط با یکدیگر را در یک گروه پیوند دهید. میتواند چندین گروه در یک فایل آزمایشی وجود داشته باشد که برای آزمایش بخشهای مختلف فایل مربوطه در دایرکتوری lib
در نظر گرفته شده است.
متد test()
دو پارامتر موقعیتی دارد: description
تست و callback
که در آن واقعاً تست را می نویسید.
حذف یک مورد از لیست را آزمایش کنید. آزمایش زیر را در همان گروه Testing App Provider
وارد کنید:
test/models/favorites_test.dart
test('An item should be removed', () {
var number = 45;
favorites.add(number);
expect(favorites.items.contains(number), true);
favorites.remove(number);
expect(favorites.items.contains(number), false);
});
تست را اجرا کنید
در خط فرمان، به دایرکتوری ریشه پروژه بروید و دستور زیر را وارد کنید:
$ flutter test test/models/favorites_test.dart
اگر همه چیز کار کند، باید پیامی شبیه به زیر مشاهده کنید:
00:06 +2: All tests passed!
فایل تست کامل: test/models/favorites_test.dart
.
برای کسب اطلاعات بیشتر در مورد آزمایش واحد، از مقدمه ای بر تست واحد دیدن کنید.
6. تست ویجت
در این مرحله کدی را به ویجت های آزمایشی اضافه می کنید. تست ویجت برای Flutter منحصر به فرد است، جایی که می توانید هر ویجت را به صورت مجزا آزمایش کنید. این مرحله صفحه HomePage
و FavoritesPage
را به صورت جداگانه آزمایش می کند.
تست ویجت به جای تابع testWidget()
test()
استفاده می کند. مانند تابع test()
، تابع testWidget()
دو پارامتر دارد: description,
و callback
، با این حال callback یک WidgetTester
به عنوان آرگومان خود می گیرد.
تستهای ویجت از TestFlutterWidgetsBinding
استفاده میکنند، کلاسی که همان منابعی را در اختیار ویجتهای شما قرار میدهد که در یک برنامه در حال اجرا دارند، به عنوان مثال اطلاعاتی درباره اندازه صفحه نمایش، توانایی زمانبندی انیمیشنها، اما بدون اجرا در داخل برنامه. در عوض، از یک محیط مجازی برای نمونه سازی ویجت استفاده می شود و سپس نتایج را اجرا می کند. در اینجا، pumpWidget
فرآیند را با گفتن به فریمورک آغاز میکند که یک ویجت خاص را درست مانند یک برنامه نصب و اندازهگیری کند.
چارچوب تست ویجت یابها را برای یافتن ویجتها فراهم میکند، برای مثال text()
, byType()
و byIcon().
این چارچوب همچنین تطبیق دهنده هایی را برای تأیید نتایج ارائه می دهد.
با آزمایش ویجت HomePage
شروع کنید.
یک فایل آزمایشی جدید ایجاد کنید
اولین آزمایش بررسی می کند که آیا پیمایش HomePage
به درستی کار می کند یا خیر.
یک فایل جدید در دایرکتوری test
ایجاد کنید و نام آن را home_test.dart
بگذارید. در فایل جدید ایجاد شده کد زیر را اضافه کنید:
test/home_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/home.dart';
Widget createHomeScreen() => ChangeNotifierProvider<Favorites>(
create: (context) => Favorites(),
child: const MaterialApp(
home: HomePage(),
),
);
void main() {
group('Home Page Widget Tests', () {
testWidgets('Testing Scrolling', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.text('Item 0'), findsOneWidget);
await tester.fling(
find.byType(ListView),
const Offset(0, -200),
3000,
);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsNothing);
});
});
}
تابع createHomeScreen()
برای ایجاد برنامه ای استفاده می شود که ویجت مورد آزمایش را در MaterialApp بارگیری می کند و در یک ChangeNotifierProvider پیچیده می شود. ویجت HomePage به هر دوی این ویجت ها نیاز دارد که در بالای آن در درخت ویجت وجود داشته باشد تا بتواند از آنها به ارث برده و به داده هایی که ارائه می دهند دسترسی داشته باشد. این تابع به عنوان یک پارامتر به تابع pumpWidget()
ارسال می شود.
در مرحله بعد، بررسی کنید که آیا فریم ورک می تواند ListView
که روی صفحه نمایش داده شده است پیدا کند یا خیر.
قطعه کد زیر را به home_test.dart
اضافه کنید:
test/home_test.dart
group('Home Page Widget Tests', () {
// BEGINNING OF NEW CONTENT
testWidgets('Testing if ListView shows up', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.byType(ListView), findsOneWidget);
});
// END OF NEW CONTENT
testWidgets('Testing Scrolling', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.text('Item 0'), findsOneWidget);
await tester.fling(
find.byType(ListView),
const Offset(0, -200),
3000,
);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsNothing);
});
});
تست را اجرا کنید
ابتدا تست را به همان روشی که تست واحد را اجرا می کنید با دستور زیر اجرا کنید:
$ flutter test test/home_test.dart
آزمایش باید به سرعت اجرا شود و شما باید پیامی مانند این را ببینید:
00:02 +2: All tests passed!
همچنین میتوانید تستهای ویجت را با استفاده از یک دستگاه یا شبیهساز اجرا کنید، که به شما امکان میدهد آزمایش را در حال اجرا تماشا کنید. همچنین به شما امکان استفاده از راه اندازی مجدد داغ را می دهد.
دستگاه خود را وصل کنید یا شبیه ساز خود را راه اندازی کنید. همچنین می توانید آزمون را به عنوان یک برنامه دسکتاپ اجرا کنید.
از خط فرمان، به دایرکتوری ریشه پروژه بروید و دستور زیر را وارد کنید:
$ flutter run test/home_test.dart
ممکن است لازم باشد دستگاهی را برای اجرای آزمایش انتخاب کنید. در این صورت، دستورالعمل ها را دنبال کنید و یک دستگاه را انتخاب کنید:
Multiple devices found:
Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web) • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"):
اگر همه چیز کار می کند، باید خروجی مشابه زیر را ببینید:
Launching test/home_test.dart on Linux in debug mode...
Building Linux application...
flutter: 00:00 +0: Home Page Widget Tests Testing if ListView shows up
Syncing files to device Linux... 62ms
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
💪 Running with sound null safety 💪
An Observatory debugger and profiler on Linux is available at: http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:00 +1: Home Page Widget Tests Testing Scrolling
The Flutter DevTools debugger and profiler on Linux is available at:
http://127.0.0.1:9100?uri=http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:02 +2: All tests passed!
در مرحله بعد، تغییراتی را در فایل آزمایشی اعمال میکنید و Shift + R
را فشار دهید تا برنامه دوباره راهاندازی شود و همه آزمایشها دوباره اجرا شوند. برنامه را متوقف نکنید.
تست های بیشتری را به گروهی که ویجت های صفحه اصلی را آزمایش می کند اضافه کنید. تست زیر را در فایل خود کپی کنید:
test/home_test.dart
testWidgets('Testing IconButtons', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.byIcon(Icons.favorite), findsNothing);
await tester.tap(find.byIcon(Icons.favorite_border).first);
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Added to favorites.'), findsOneWidget);
expect(find.byIcon(Icons.favorite), findsWidgets);
await tester.tap(find.byIcon(Icons.favorite).first);
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Removed from favorites.'), findsOneWidget);
expect(find.byIcon(Icons.favorite), findsNothing);
});
این آزمایش تأیید میکند که ضربه زدن روی IconButton
از Icons.favorite_border
(یک قلب باز) به Icons.favorite
(یک قلب پر شده) تغییر میکند و پس از ضربه زدن دوباره به Icons.favorite_border
برمیگردد.
Shift + R
را وارد کنید. این داغ برنامه را دوباره راه اندازی می کند و همه آزمایش ها را دوباره اجرا می کند.
فایل تست کامل: test/home_test.dart
.
از همین فرآیند برای تست FavoritesPage
با کد زیر استفاده کنید. همین مراحل را دنبال کنید و اجرا کنید.
test/favorites_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';
late Favorites favoritesList;
Widget createFavoritesScreen() => ChangeNotifierProvider<Favorites>(
create: (context) {
favoritesList = Favorites();
return favoritesList;
},
child: const MaterialApp(
home: FavoritesPage(),
),
);
void addItems() {
for (var i = 0; i < 10; i += 2) {
favoritesList.add(i);
}
}
void main() {
group('Favorites Page Widget Tests', () {
testWidgets('Test if ListView shows up', (tester) async {
await tester.pumpWidget(createFavoritesScreen());
addItems();
await tester.pumpAndSettle();
expect(find.byType(ListView), findsOneWidget);
});
testWidgets('Testing Remove Button', (tester) async {
await tester.pumpWidget(createFavoritesScreen());
addItems();
await tester.pumpAndSettle();
var totalItems = tester.widgetList(find.byIcon(Icons.close)).length;
await tester.tap(find.byIcon(Icons.close).first);
await tester.pumpAndSettle();
expect(tester.widgetList(find.byIcon(Icons.close)).length,
lessThan(totalItems));
expect(find.text('Removed from favorites.'), findsOneWidget);
});
});
}
این تست بررسی می کند که آیا با فشار دادن دکمه بستن (حذف) یک مورد ناپدید می شود یا خیر.
برای کسب اطلاعات بیشتر در مورد تست ویجت، به آدرس زیر مراجعه کنید:
7. تست رابط کاربری اپلیکیشن با تست های یکپارچه سازی
تستهای یکپارچهسازی برای آزمایش نحوه کار تک تک تکههای یک برنامه با هم به عنوان یک کل استفاده میشوند. کتابخانه integration_test
برای انجام تست های ادغام در Flutter استفاده می شود. این نسخه فلاتر از Selenium WebDriver، Protractor، Espresso، یا Earl Grey است. این بسته از flutter_driver
به صورت داخلی برای اجرای تست روی دستگاه استفاده میکند.
نوشتن تستهای یکپارچهسازی در فلاتر شبیه به نوشتن تستهای ویجت است، با این تفاوت که تستهای یکپارچهسازی روی یک دستگاه تلفن همراه، مرورگر یا برنامه دسکتاپ به نام دستگاه هدف اجرا میشوند.
تست رو بنویس
یک دایرکتوری به نام integration_test
در دایرکتوری ریشه پروژه ایجاد کنید و در آن دایرکتوری یک فایل جدید به نام app_test.dart
ایجاد کنید.
integration_test/app_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:testing_app/main.dart';
void main() {
group('Testing App', () {
testWidgets('Favorites operations test', (tester) async {
await tester.pumpWidget(const TestingApp());
final iconKeys = [
'icon_0',
'icon_1',
'icon_2',
];
for (var icon in iconKeys) {
await tester.tap(find.byKey(ValueKey(icon)));
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Added to favorites.'), findsOneWidget);
}
await tester.tap(find.text('Favorites'));
await tester.pumpAndSettle();
final removeIconKeys = [
'remove_icon_0',
'remove_icon_1',
'remove_icon_2',
];
for (final iconKey in removeIconKeys) {
await tester.tap(find.byKey(ValueKey(iconKey)));
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Removed from favorites.'), findsOneWidget);
}
});
});
}
تست را اجرا کنید
دستگاه خود را وصل کنید یا شبیه ساز خود را راه اندازی کنید. همچنین می توانید آزمون را به عنوان یک برنامه دسکتاپ اجرا کنید.
در خط فرمان، به دایرکتوری ریشه پروژه بروید و دستور زیر را وارد کنید:
$ flutter test integration_test/app_test.dart
اگر همه چیز کار کند، باید خروجی مشابه زیر را ببینید:
Multiple devices found:
Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web) • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"): 1
00:00 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart B00:08 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart
00:26 +1: All tests passed!
8. تست عملکرد برنامه با Flutter Driver
یک تست عملکرد بنویسید
یک فایل آزمایشی جدید با نام perf_test.dart در پوشه integration_test با محتوای زیر ایجاد کنید:
integration_test/perf_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:testing_app/main.dart';
void main() {
group('Testing App Performance', () {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
testWidgets('Scrolling test', (tester) async {
await tester.pumpWidget(const TestingApp());
final listFinder = find.byType(ListView);
await binding.traceAction(() async {
await tester.fling(listFinder, const Offset(0, -500), 10000);
await tester.pumpAndSettle();
await tester.fling(listFinder, const Offset(0, 500), 10000);
await tester.pumpAndSettle();
}, reportKey: 'scrolling_summary');
});
});
}
تابع ensureInitialized()
بررسی می کند که آیا درایور تست یکپارچه سازی مقداردهی اولیه شده است، در صورت نیاز آن را مجدداً مقداردهی می کند. تنظیم framePolicy
روی fullyLive
برای آزمایش کدهای متحرک خوب است.
این تست در لیست موارد بسیار سریع پیمایش میکند و سپس تا انتها به بالا پیمایش میکند. تابع traceAction()
اقدامات را ثبت می کند و یک خلاصه جدول زمانی تولید می کند.
نتایج عملکرد را ثبت کنید
برای گرفتن نتایج، یک پوشه به نام test_driver
با فایلی به نام perf_driver.dart
ایجاد کنید و کد زیر را اضافه کنید:
test_driver/perf_driver.dart
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_summary'] as Map<String, dynamic>);
final summary = driver.TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(
'scrolling_summary',
pretty: true,
includeSummary: true,
);
}
},
);
}
تست را اجرا کنید
دستگاه خود را وصل کنید یا شبیه ساز خود را راه اندازی کنید.
در خط فرمان، به دایرکتوری ریشه پروژه بروید و دستور زیر را وارد کنید:
$ flutter drive \
--driver=test_driver/perf_driver.dart \
--target=integration_test/perf_test.dart \
--profile \
--no-dds
اگر همه چیز کار کند، باید خروجی مشابه زیر را ببینید:
Running "flutter pub get" in testing_app...
Resolving dependencies...
archive 3.3.2 (3.3.6 available)
collection 1.17.0 (1.17.1 available)
js 0.6.5 (0.6.7 available)
matcher 0.12.13 (0.12.14 available)
meta 1.8.0 (1.9.0 available)
path 1.8.2 (1.8.3 available)
test 1.22.0 (1.23.0 available)
test_api 0.4.16 (0.4.18 available)
test_core 0.4.20 (0.4.23 available)
vm_service 9.4.0 (11.0.1 available)
webdriver 3.0.1 (3.0.2 available)
Got dependencies!
Running Gradle task 'assembleProfile'... 1,379ms
✓ Built build/app/outputs/flutter-apk/app-profile.apk (14.9MB).
Installing build/app/outputs/flutter-apk/app-profile.apk... 222ms
I/flutter ( 6125): 00:04 +1: Testing App Performance (tearDownAll)
I/flutter ( 6125): 00:04 +2: All tests passed!
All tests passed.
پس از اتمام موفقیت آمیز تست، دایرکتوری ساخت در ریشه پروژه شامل دو فایل است:
-
scrolling_summary.timeline_summary.json
حاوی خلاصه است. فایل را با هر ویرایشگر متنی باز کنید تا اطلاعات موجود در آن را مرور کنید. -
scrolling_summary.timeline.json
شامل اطلاعات کامل جدول زمانی است.
برای جزئیات بیشتر در مورد تست ادغام، به آدرس زیر مراجعه کنید:
9. تبریک!
شما نرم افزار Codelab را تکمیل کرده اید و روش های مختلفی را برای آزمایش یک برنامه Flutter یاد گرفته اید.
چیزی که یاد گرفتی
- نحوه آزمایش ارائه دهندگان با کمک تست های واحد
- نحوه تست ویجت ها با استفاده از چارچوب تست ویجت
- نحوه تست UI برنامه با استفاده از تست های یکپارچه سازی
- نحوه تست عملکرد برنامه با استفاده از تست های یکپارچه سازی
برای کسب اطلاعات بیشتر در مورد تست کردن در فلاتر، به سایت مراجعه کنید