29 β Testing, debugging va ishlab chiqarish¶
β¬ οΈ Oldingi: 28 β Platforma, paketlar va moslashuv Β· π README Β· Keyingi: 30 β Yakuniy loyiha: to'liq ilova β‘οΈ
Bu bobda: ilovangiz tayyor bo'lib qoldi β endi uni ishonchli qilish va odamlarga yetkazish kerak. Avval nega test yozish kerakligini tushunasiz, so'ng test piramidasining uch qavatini o'rganasiz: tez va arzon unit testlar (sof mantiq β Cubit, util, model;
mocktailbilan soxta obyektlar vabloc_test), widget testlar (testWidgets,tester.pumpWidget,find.*,tester.tap) va kamsonli integratsion testlar (haqiqiy qurilmada). Keyin debugging β qizil xato ekranini o'qish,debugPrint, Flutter DevTools (Inspector, Performance, Memory),flutter analyzevadart format. So'ng unumdorlik (performance) β kadr byudjeti (16 ms), "jank",constwidgetlar, dangasa ro'yxatlar vaRepaintBoundary. Nihoyat ilovani chiqarish (release) βflutter build appbundle, imzolash (keystore), versiyalash, ikonka/splash va do'konga (Play Store / App Store) yuborish. Oxirida to'liq ishga tushirish nazorat ro'yxati (checklist).
Nega umuman test yozamiz?¶
Tasavvur qiling: siz ilovaga yangi xususiyat qo'shdingiz. Bir-ikki ekranni qo'lda ochib, "ishlayapti shekilli" deb xulosa qildingiz. Lekin siz ko'rmagan yana o'nlab ekran bor β va ulardan biri sizning o'zgartirishingiz tufayli buzilgan bo'lishi mumkin. Buni qachon bilib olasiz? Foydalanuvchi shikoyat qilganda. Bu β eng yomon payt.
Test β bu kodingizni avtomatik tekshiradigan boshqa kod. Siz bir marta "bu funksiya 2 + 2 ga 4 qaytarishi kerak" deb yozasiz, keyin har safar flutter test deganingizda kompyuter buni siz uchun soniyalarda tekshiradi. Testlar ikki katta foyda beradi:
- Regressiyani ushlaydi. "Regressiya" β ilgari ishlagan narsaning yangi o'zgartirish tufayli buzilishi. Testlar bo'lsa, buzilgan joyni darhol, foydalanuvchidan oldin bilib olasiz.
- Qo'rqmasdan refaktoring qilish imkonini beradi. Kodni tozalash, qayta yozish β har doim "bir narsani buzib qo'ymadimmi?" degan qo'rquv bilan keladi. Testlar yashil bo'lib tursa, dadil o'zgartirasiz: agar bir narsa buzilsa, test qizil bo'ladi.
π‘ Asosiy g'oya: test yozish "qo'shimcha ish" emas β bu kelajakdagi o'zingizga sovg'a. Bugun yozilgan test ertaga sizni tunda turib bug qidirishdan saqlaydi.
Test piramidasi β uch qavat¶
Hamma test bir xil emas. Ularni piramida ko'rinishida tasavvur qilish β sohada eng mashhur va foydali model:
Yuqoridagi rasmda ko'rganingizdek, piramidaning asosi keng (ko'p test), cho'qqisi tor (kam test). Sababi: pastdagi testlar tez va arzon, yuqoridagilar sekin va qimmat. Shuning uchun ko'p sonli unit test, o'rtacha widget test va ozgina integratsion test yozish β sog'lom muvozanat.
| Qavat | Nimani tekshiradi | Tezligi | Soni |
|---|---|---|---|
| Unit (asos) | Sof mantiq: bitta funksiya, Cubit, model | Juda tez (millisekund) | Ko'p |
| Widget (o'rta) | Bitta widget yakka holda: ko'rinish + bosish | O'rtacha | O'rtacha |
| Integratsion (cho'qqi) | Butun ilova haqiqiy qurilmada | Sekin | Kam |
Endi har bir qavatni alohida ko'rib chiqamiz.
Unit testlar β sof mantiqni tekshirish¶
Unit test β eng kichik, eng tez test. U bitta "birlik" (unit) β masalan bitta funksiya, bitta sinf metodi yoki bitta Cubit β ni UI'siz, tarmoqsiz, sof holda tekshiradi.
Hamma test package:flutter_test (yoki sof Dart loyihasida package:test) dan keladi. Asosiy uchta vosita:
test('nomi', () { ... })β bitta testni e'lon qiladi.expect(haqiqiy, kutilgan)β natija kutilganidek ekanini tekshiradi. Bu testning yuragi.group('nomi', () { ... })β bog'liq testlarni guruhga yig'adi.
Testlar test/ papkasida, nomi *_test.dart bilan tugaydigan fayllarda turadi. Mana oddiy util funksiya testi:
import 'package:flutter_test/flutter_test.dart';
// Sinaladigan sof funksiya
int qoshish(int a, int b) => a + b;
void main() {
group('qoshish', () {
test('ikki musbat sonni qo\'shadi', () {
expect(qoshish(2, 3), equals(5));
});
test('manfiy son bilan ishlaydi', () {
expect(qoshish(-1, 1), equals(0));
});
});
}
equals(5) β bu matcher (moslashtiruvchi): "natija 5 ga teng bo'lsin" degani. Boshqa keng tarqalgan matcherlar: isTrue, isFalse, isNull, isNotNull, greaterThan(10), throwsException (xato tashlashini tekshirish).
Cubit'ni test qilish¶
Eng foydali unit test β holat boshqaruvi mantig'ini tekshirish. 26-bobdagi CounterCubitni eslang β uni testlash juda oson, chunki u sof Dart: kiritasiz, holatni tekshirasiz.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
void main() {
group('CounterCubit', () {
test('boshlang\'ich holati 0', () {
expect(CounterCubit().state, equals(0));
});
test('increment holatni 1 ga oshiradi', () {
final cubit = CounterCubit();
cubit.increment();
expect(cubit.state, equals(1));
});
});
}
bloc_test bilan blocni tekshirish¶
Bloc/Cubit uchun maxsus bloc_test paketi bor β u "ushbu hodisalardan keyin holat shu ketma-ketlikda chiqishi kerak" degan tekshiruvni yengillashtiradi:
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
blocTest<CounterCubit, int>(
'increment -> increment qilingach [1, 2] chiqaradi',
build: () => CounterCubit(),
act: (cubit) => cubit..increment()..increment(),
expect: () => [1, 2],
);
}
build: β sinaladigan cubitni yaratadi, act: β unga ta'sir qiladi, expect: β chiqishi kutilgan holatlar ro'yxati. Bu Cubit testini ancha ixcham qiladi.
Mocking β mocktail bilan soxta obyektlar¶
Ko'pincha sinaladigan kod boshqa narsaga bog'liq bo'ladi β masalan ma'lumotni internetdan oladigan repository. Testda haqiqiy internetga chiqishni xohlamaymiz: u sekin, ishonchsiz va testni serverga bog'lab qo'yadi. Yechim β mock (soxta) obyekt: u haqiqiy obyektga o'xshab ko'rinadi, lekin biz aytgan tayyor javobni qaytaradi.
Buning uchun mocktail paketi ishlatiladi (mockito ham bor, lekin mocktail koddan oldindan generatsiya talab qilmaydi β soddaroq):
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
// Haqiqiy interfeys
abstract class WeatherRepository {
Future<int> harorat(String shahar);
}
// Soxta nusxa
class MockWeatherRepository extends Mock implements WeatherRepository {}
void main() {
test('repository qaytargan haroratni o\'qiydi', () async {
final repo = MockWeatherRepository();
// "harorat('Toshkent') chaqirilsa, 25 qaytar" deb o'rgatamiz
when(() => repo.harorat('Toshkent')).thenAnswer((_) async => 25);
final natija = await repo.harorat('Toshkent');
expect(natija, equals(25));
// Metod haqiqatan chaqirilganini tekshiramiz
verify(() => repo.harorat('Toshkent')).called(1);
});
}
Asosiy uchta amal: when(...).thenAnswer(...) (soxta javobni o'rgatish β asinxron uchun, 09-bobdagi Futureni eslang; sinxron uchun thenReturn), verify(...) (metod chaqirilganini tasdiqlash), va Mock dan meros olish.
π‘ Oltin qoida β xulq-atvorni test qiling, ichki tuzilmani emas. "Tugma bosilsa, hisob 1 ga oshadi" degan xulqni tekshiring; "ichida
_counto'zgaruvchisi bor" degan ichki detalni emas. Aks holda kodni biroz qayta yozishingiz bilan barcha testlar buziladi β bu testlarni foydadan ko'ra to'siqqa aylantiradi.
Widget testlar β UI'ni yakka holda tekshirish¶
Unit test mantiqni tekshiradi, lekin "tugma bosilganda matn yangilanadimi?" degan UI savoliga javob bermaydi. Buni widget test hal qiladi: u bitta widgetni soxta ekranda quradi, unga teginadi, va ko'rinishni tekshiradi β bularning hammasi haqiqiy qurilmasiz, juda tez.
Asosiy farq: test(...) o'rniga testWidgets(...) ishlatiladi va u sizga WidgetTester tester beradi β bu soxta ekranni boshqaradigan vosita.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Hisoblagich tugma bosilganda oshadi', (tester) async {
// 1) Widgetni soxta ekranga quramiz
await tester.pumpWidget(const MaterialApp(home: CounterPage()));
// 2) Boshida "0" ko'rinishini tekshiramiz
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// 3) "+" ikonkasiga tegamiz
await tester.tap(find.byIcon(Icons.add));
// 4) Kadrni qayta chizamiz (setState'dan keyin shart!)
await tester.pump();
// 5) Endi "1" ko'rinishi kerak
expect(find.text('1'), findsOneWidget);
});
}
Bu testni bo'laklab tushunamiz:
tester.pumpWidget(...)β widgetni soxta ekranga "ekib" (pump) quradi. Diqqat: widgetniMaterialApp(yoki kamidaMaterialApp(home: ...)) ichiga o'rang β aks holdaTheme,Directionalitykabi kontekst topilmay xato bo'ladi.find.*β ekrandan widget topadi:find.text('0')(matn bo'yicha),find.byIcon(Icons.add)(ikonka bo'yicha),find.byKey(...)(kalit bo'yicha),find.byType(ElevatedButton)(tur bo'yicha).- Matcherlar:
findsOneWidget(aniq bitta topildi),findsNothing(topilmadi),findsNWidgets(3)(aniq 3 ta),findsWidgets(bir yoki ko'p). tester.tap(...)β topilgan widgetga teginadi (boshqalar:tester.enterText(...),tester.drag(...)).tester.pump()β kadrni qayta chizadi. Buni unutsangiz, ekran eski holatda qoladi va test "1 topilmadi" deb yiqiladi.
pump va pumpAndSettle farqi¶
tester.pump()β bitta kadrni qayta chizadi. OddiysetStateo'zgarishlari uchun yetarli.tester.pumpAndSettle()β animatsiya yoki kechikadigan o'zgarish tinchiguncha (settle) kadrlarni qayta-qayta chizadi. Masalan ekran o'tish animatsiyasi yokiSnackBarchiqishini kutish kerak bo'lganda ishlatiladi.
π‘ Sodda qoida: oddiy holat o'zgarishida
pump(), animatsiya/o'tish tugashini kutish kerak bo'lsapumpAndSettle(). Noto'g'risini ishlatish testni yiqitadi yoki muzlatib qo'yadi.
Integratsion testlar β butun ilova qurilmada¶
Unit va widget testlar soxta muhitda, qurilmasiz ishlaydi. Lekin ba'zan "ilova haqiqiy telefonda, boshidan oxirigacha, haqiqiy oqim bilan ishlaydimi?" degan savol qoladi: login β bosh sahifa β buyurtma berish. Buni integratsion test tekshiradi.
Buning uchun integration_test paketi loyihangizga qo'shiladi (u Flutter SDK bilan keladi). Testlar integration_test/ papkasida yoziladi va haqiqiy qurilmada/emulyatorda quyidagicha ishga tushiriladi:
Kodi widget testga juda o'xshaydi (tester, find, tap), lekin butun ilovani ishga tushiradi. Ular sekin (haqiqiy qurilma kerak), shuning uchun piramidaning cho'qqisida β kam sonda, faqat eng muhim oqimlar uchun yoziladi.
Testlarni ishga tushirish va qamrov (coverage)¶
Hamma testni ishga tushirish oddiy:
flutter test # barcha unit + widget testlar
flutter test test/cubit_test.dart # bitta fayl
flutter test --coverage # qamrov (coverage) ma'lumoti bilan
--coverage kodingizning qancha qismi testlar bilan o'ralganini o'lchaydi va coverage/lcov.info fayliga yozadi. Lekin diqqat: yuqori foiz o'z-o'zidan sifat kafolati emas β muhim mantiq o'ralganligi raqamdan muhimroq. 100% qamrov uchun ahamiyatsiz testlar yozishdan ko'ra, asosiy mantiqni puxta sinash afzal.
Debugging β xatolarni tushunish va DevTools¶
Test yashil bo'lsa ham, ishlab chiqish jarayonida xatolar muqarrar. Flutter ularni topishda yordam beradigan kuchli vositalarga ega.
Qizil xato ekrani va stack trace¶
Build paytida xato bo'lsa, Flutter mashhur qizil xato ekrani (ko'pincha "red screen of death" deyiladi) ni ko'rsatadi β qizil fonda xato matni. Bu qo'rqinchli ko'rinsa-da, aslida do'st: u nima buzilganini va qaysi qatorda ekanini aytadi. Stack trace (xato izi) β xato qaysi funksiyalar zanjiri orqali yuzaga kelganini ko'rsatadigan ro'yxat; eng yuqoridagi qator odatda sizning kodingizdagi aybdor joy.
debugPrint va assert¶
Eng sodda debugging β konsolga chop etish. Flutter'da print o'rniga debugPrint ishlating: u juda uzun matnni kesib, konsolni to'ldirib yubormaydi, va release rejimida osongina o'chiriladi.
assert β faqat debug rejimida ishlaydigan tekshiruv: shart noto'g'ri bo'lsa, ilovani darhol to'xtatib, xatoni ko'rsatadi. "Bu yerga null kelmasligi kerak" kabi taxminlarni himoyalash uchun ajoyib (release buildda butunlay olib tashlanadi, demak tezlikka ta'sir qilmaydi):
Flutter DevTools β vizual asboblar to'plami¶
DevTools β Flutter'ning brauzerda ochiladigan kuchli debugging asboblar to'plami. Uni IDE'dan (VS Code / Android Studio) tugma bilan yoki terminalda dart devtools bilan ochasiz. Asosiy panellar:
- Inspector β widget daraxtini (widget tree) ko'rsatadi: ilovangiz qaysi widgetlardan tuzilganini, ularning xossalarini ko'rasiz. "Layout Explorer" esa
Row/Columnning joylashuvini vizual tushuntiradi β layout muammolarini hal qilishda bebaho. - Performance β kadrlar qancha vaqt olishini ko'rsatadi (pastda batafsil).
- Memory β xotira ishlatilishini kuzatadi (xotira "oqishi"ni β memory leak β topish uchun).
- Network β ilova qilgan tarmoq so'rovlarini ko'rsatadi.
- Logging β
debugPrintva tizim loglari oqimi.
Birinchi himoya: flutter analyze va dart format¶
Xatolarni yozayotgan paytdayoq ushlash debugdan ham yaxshiroq. Ikki buyruq buni qiladi:
flutter analyze # statik tahlil: ishlatilmagan o'zgaruvchi, null xavfi, yomon naqsh
dart format . # kodni standart uslubda avtomatik tekislaydi
flutter analyze β kodni ishga tushirmasdan tekshiradi va potensial muammolarni (xato bo'lishi mumkin bo'lgan joylar, foydasiz kod) ro'yxatlaydi. dart format esa butun jamoaning kodi bir xil ko'rinishini ta'minlaydi. Bu ikkalasini har commit'dan oldin ishga tushirish β professional odat.
Unumdorlik (performance) β silliq 60/120 kadr¶
Foydalanuvchi ilovangizni "silliq" yoki "tutab turadi" deb his qiladi. Buning ortida aniq matematika bor.
Kadr byudjeti va "jank"¶
Ekran soniyasiga ma'lum sonda yangilanadi: ko'pchilik qurilmada 60 FPS (soniyasiga 60 kadr), yangiroqlarida 120 FPS. 60 FPS demak β har bir kadr uchun atigi ~16 millisekund vaqt bor (120 FPS uchun ~8 ms). Flutter shu vaqt ichida kadrni qurib (build), joylab (layout) va chizib (paint) ulgurishi kerak.
Agar bir kadr 16 ms dan oshib ketsa, u kadr tushib qoladi (dropped frame) β ekran bir lahza qotadi. Mana shu β "jank" (silkinish, tutash). Foydalanuvchi buni darhol sezadi.
Rasmda ko'rganingizdek, kadr 16 ms byudjetiga sig'sa β silliq (yashil); oshib ketsa β jank (qizil). Yaxshi xabar: 2026-yilda Flutter standart Impeller renderini ishlatadi β u eski renderga nisbatan kadrlarni ancha barqaror va silliq chizadi, "birinchi animatsiya tutashi" muammosini bartaraf qiladi.
Eng ko'p uchraydigan yutuqlar¶
Jankning asosiy sababi β kadrda keraksiz ish qilish. Mana eng samarali tuzatishlar:
constkonstruktorlar/widgetlar. Widgetconstbo'lsa, Flutter uni qayta qurmaydi β bir marta qurib, qayta-qayta ishlatadi.const Text('Salom')har rebuild'da tejaydi. Bu eng oson va eng katta yutuqlardan biri.- Granular (mayda) holat β kamroq rebuild. Butun ekranni qayta qurish o'rniga, faqat o'zgargan kichik qismni qayta quring. 24/25-boblardagi holat boshqaruvi vositalari (
Consumer,Selector,BlocBuilder) aynan shu uchun: ular faqat kerakli bo'lakni yangilaydi. ListView.builderβ dangasa ro'yxat. Ro'yxatlar bobidan eslang: u faqat ekrandagi elementlarni quradi. Uzun ro'yxatdaListView(children: [...])o'rniga doimobuilder.RepaintBoundary. Tez-tez qayta chiziladigan qismni (masalan animatsiya) qolganidan ajratib, "faqat shu qismni qayta chiz" deydi β qolgan ekran behuda qayta chizilmaydi.buildichida og'ir ish qilmang.buildmetodi tez-tez (har kadrda) chaqirilishi mumkin. Unda fayl o'qish, murakkab hisob, tarmoq so'rovi qilmang β bularni tashqariga (initState, repository) chiqaring.- Rasmlarni keshlang. Tarmoqdan kelgan rasmlar uchun
cached_network_imagekabi paket har safar qayta yuklamaslik uchun keshlaydi.
DevTools Performance bilan profillash¶
Qaerda jank borligini taxmin qilmang β o'lchang. DevTools'ning Performance paneli har kadrni vaqt o'qiga (timeline) chizadi. U ikkita asosiy oqimni ko'rsatadi: UI thread (Dart kodingiz β build/layout) va Raster thread (chizish/GPU). Qaysi biri 16 ms dan oshsa β muammo o'sha tomonda.
β οΈ Eng muhim qoida: unumdorlikni
--profilerejimida o'lchang, debug rejimida emas! Debug build qo'shimcha tekshiruvlar tufayli ataylab sekin β uning tezligi haqiqiy emas.flutter run --profilehaqiqiy unumdorlikni ko'rsatadi (release'ga yaqin, lekin profillash asboblari yoqilgan).
Ilovani chiqarish (build va release)¶
Ilova tayyor, testlar yashil β endi uni do'konga chiqaramiz. Kod do'kongacha qanday yo'l bosishini ko'rib chiqamiz:
Release build buyruqlari¶
Android uchun ikki format bor:
flutter build appbundle # AAB β Play Store uchun TAVSIYA ETILGAN
flutter build apk # APK β to'g'ridan-to'g'ri o'rnatish/sinov uchun
flutter build apk --split-per-abi # har protsessor turi uchun alohida, kichikroq APK
appbundle (AAB) β Play Store'ning afzal formati: Google har foydalanuvchining qurilmasiga moslab optimallashtirilgan kichik APK yaratadi. Oddiy apk esa to'g'ridan-to'g'ri o'rnatish yoki sinov uchun qulay.
iOS uchun (faqat Mac + Xcode kerak):
Hamma release buildga --release bayrog'i (build appbundle/ipa'da u standart) yoki rejim ko'zda tutiladi β bu debug tekshiruvlarsiz, optimallashtirilgan, tez build beradi.
Imzolash (signing) β eng muhim qadam¶
Do'kon faqat imzolangan ilovani qabul qiladi. Imzo β ilova haqiqatan sizdan kelganini isbotlaydi.
Android β keystore: avval bir marta kalit (keystore) yaratasiz, so'ng uni loyihaga ulaysiz. android/key.properties faylida kalit ma'lumoti turadi (uni hech qachon git'ga qo'shmang!):
So'ng android/app/build.gradle (yoki .gradle.kts) faylida signingConfigs shu key.propertiesni o'qiydigan qilib sozlanadi. Bir marta sozlasangiz, keyingi har release shu kalit bilan avtomatik imzolanadi.
iOS β sertifikat va provisioning: Apple ekotizimida imzo sertifikat (certificate) va provisioning profile orqali boshqariladi. Buni odatda Xcode yoki App Store Connect'da sozlaysiz. (Apple Developer hisobi β yiliga to'lov talab qiladi.)
Versiyalash¶
Har release ilovaning versiyasini oshirishi kerak β do'kon eski va yangi nusxani shu bilan ajratadi. Versiya pubspec.yaml da turadi:
1.0.0β odamlarga ko'rinadigan versiya nomi (Android'daversionName, iOS'da marketing version).+1β ichki, har release'da o'sishi shart bo'lgan build raqami (Android'daversionCode, iOS'da build number). Yangi nusxa eskidan kattaroq raqamga ega bo'lishi kerak.
Ikonka, splash va kod himoyasi¶
- App ikonka:
flutter_launcher_iconspaketi bitta rasmdan barcha platforma/o'lchamlar uchun ikonka generatsiya qiladi. - Splash screen (ochilish ekrani):
flutter_native_splashilova yuklanayotganda ko'rinadigan ekranni sozlaydi. - Obfuscation (kodni chalkashtirish): release buildda kodingiz nomlarini chalkashtirib, teskari muhandislikni qiyinlashtirish uchun:
--split-debug-info β chalkashtirilgan stack trace'larni keyin tiklash uchun "symbol" fayllarini saqlaydi. Bu fayllarni saqlab qo'ying β release'dagi xatoni o'qish uchun kerak bo'ladi.
Do'konga yuborish¶
- Play Console (Android): AAB faylni yuklaysiz, do'kon sahifasini to'ldirasiz (skrinshotlar, tavsif, ikonka, maxfiylik siyosati), va tekshiruvga (review) yuborasiz.
- App Store Connect (iOS): IPA'ni Xcode yoki Transporter orqali yuklaysiz, metama'lumot va skrinshotlarni to'ldirasiz, Apple'ning tekshiruviga yuborasiz (Apple tekshiruvi qattiqroq va sekinroq).
Ikkala do'kon ham maxfiylik siyosati (privacy policy) va ilova qanday ma'lumot to'plashi haqida ma'lumot talab qiladi β buni oldindan tayyorlang.
CI/CD β avtomatlashtirish (qisqacha)¶
Har release'ni qo'lda qurib, imzolab, yuklash zerikarli va xatoga moyil. CI/CD (uzluksiz integratsiya/yetkazib berish) buni avtomatlashtiradi: kod git'ga yuklanganda serverda testlar avtomatik ishlaydi, build qilinadi, hatto do'konga yuboriladi. Mashhur vositalar: GitHub Actions (bepul, git bilan integratsiya), Codemagic (Flutter'ga maxsus), Fastlane (do'konga yuborishni avtomatlashtiradi). Boshlovchi uchun: avval qo'lda chiqarishni o'rganing, jamoangiz o'sgach CI/CD'ga o'ting.
Ishga tushirish nazorat ro'yxati (checklist)¶
Ilovani do'konga chiqarishdan oldin shu ro'yxatdan o'ting:
- [ ]
flutter testβ barcha testlar yashil. - [ ]
flutter analyzeβ hech qanday ogohlantirish/xato yo'q. - [ ]
dart format .β kod tekislangan. - [ ] Release build ishlaydi (
flutter build appbundle/ipaxatosiz). - [ ] Ikonka va splash sozlangan (
flutter_launcher_icons,flutter_native_splash). - [ ] Imzolash sozlangan (Android keystore / iOS sertifikat);
key.propertiesgit'da emas. - [ ] Versiya oshirilgan (
pubspec.yamldagi+buildraqami). - [ ]
--obfuscate --split-debug-infoishlatilgan, symbol fayllar saqlangan. - [ ] Do'kon aktivlari tayyor (skrinshotlar, tavsif, kategoriya).
- [ ] Maxfiylik siyosati mavjud va havola berilgan.
- [ ] Haqiqiy qurilmada release build sinab ko'rilgan.
Keyingi qadam¶
Bu bobda ilovangizni ishonchli va chiqarishga tayyor qilishni o'rgandingiz: test piramidasi (unit β widget β integratsion), mocktail bilan mocking va bloc_test, DevTools bilan debugging, flutter analyze/dart format, kadr byudjeti va unumdorlik yutuqlari, va nihoyat imzolash, versiyalash va do'konga yuborish β to'liq nazorat ro'yxati bilan.
Endi sizda Flutter ilovasini qurishdan yetkazishgacha barcha ko'nikma bor. Keyingi 30-bobda β yakuniy loyiha: o'rgangan hamma narsani β widgetlar, navigatsiya, holat boshqaruvi, tarmoq, test va release β bitta to'liq, real ilovada birlashtiramiz.
Mashqlar¶
Oson¶
- Test piramidasining uch qavatini ayting. Nega asosida (eng ko'p) unit test, cho'qqisida (eng kam) integratsion test turadi?
test(...)vaexpect(...)har biri nima qiladi?expect(qoshish(2, 2), equals(4))qatorini o'z so'zlaringiz bilan tushuntiring.- Widget testda
tester.tap(...)dan keyintester.pump()ni chaqirishni unutsangiz nima bo'ladi va nega? - Kadr byudjeti nima? 60 FPS uchun bitta kadrga necha millisekund vaqt bor, va bu vaqtdan oshib ketsa nima yuz beradi (bu hodisa qanday ataladi)?
O'rta¶
- Quyidagi sof funksiya uchun
groupichida ikkita unit test yozing:bool juftmi(int n) => n % 2 == 0. Biri juft son, biri toq son uchun bo'lsin. find.text('Saqlash'),find.byIcon(Icons.delete),find.byType(ElevatedButton)β uchalasi nimani topadi?findsOneWidgetvafindsNothingmatcherlari orasidagi farq nima?mocktaildawhen(() => repo.harorat('Toshkent')).thenAnswer((_) async => 25)qatori nima qiladi? Nega testda haqiqiy repository o'rniga mock ishlatamiz (kamida ikkita sabab)?
Qiyin¶
- Bir o'quvchi
flutter run(debug rejim) da ilovasini o'lchab, "juda sekin, jank bor" deb xulosa qildi. Uning xulosasi nega ishonchsiz va u nimani qilishi kerak edi? pubspec.yamldaversion: 1.2.0+5turibdi.1.2.0va+5har biri nimani anglatadi? Yangi release chiqarayotganda qaysi qismni o'zgartirish shart va nega?- Bir jamoa ilovani imzolashda
android/key.propertiesfaylini git'ga (ochiq repozitoriyga) qo'shib yuborgan. Bu nega jiddiy xavf, va to'g'ri amaliyot qanday bo'lishi kerak edi?
Yechimlar
1. Uch qavat: unit (sof mantiq β funksiya/Cubit/model), widget (bitta widget yakka holda β ko'rinish va bosish), integratsion (butun ilova haqiqiy qurilmada). Asosida unit testlar ko'p, chunki ular tez va arzon (millisekundda, qurilmasiz ishlaydi); cho'qqisida integratsion testlar kam, chunki ular sekin va qimmat (haqiqiy qurilma kerak). Shu muvozanat tez fikr-mulohaza beradi.
2. test('nomi', () { ... }) β bitta testni e'lon qiladi (nom + ichida bajariladigan kod). expect(haqiqiy, kutilgan) β natija kutilganidek ekanini tekshiradi; mos kelmasa test yiqiladi. expect(qoshish(2, 2), equals(4)) β "qoshish(2, 2) ning natijasi 4 ga teng bo'lsin" degani; agar funksiya 4 dan boshqa narsa qaytarsa, test qizil bo'ladi.
3. tester.pump() ni unutsangiz, ekran eski holatda qoladi β bosish holatni o'zgartirgan bo'lsa ham, Flutter kadrni qayta chizmaydi, shuning uchun keyingi expect(find.text('1'), findsOneWidget) "1 topilmadi" deb yiqiladi. Sababi: tap faqat hodisani yuboradi; UI'ni yangilash uchun yangi kadr chizilishi kerak, buni pump() qiladi.
4. Kadr byudjeti β bitta kadrni qurib, joylab va chizib ulgurish uchun beriladigan vaqt. 60 FPS uchun bu ~16 ms (1000 ms Γ· 60). Bu vaqtdan oshsa, kadr tushib qoladi (dropped frame) β ekran bir lahza qotadi; bu hodisa "jank" (silkinish/tutash) deb ataladi va foydalanuvchi uni darhol sezadi.
5.
import 'package:flutter_test/flutter_test.dart';
bool juftmi(int n) => n % 2 == 0;
void main() {
group('juftmi', () {
test('juft son uchun true qaytaradi', () {
expect(juftmi(4), isTrue);
});
test('toq son uchun false qaytaradi', () {
expect(juftmi(7), isFalse);
});
});
}
6. find.text('Saqlash') β ekranda 'Saqlash' matnli widgetni topadi. find.byIcon(Icons.delete) β Icons.delete ikonkali widgetni topadi. find.byType(ElevatedButton) β turi ElevatedButton bo'lgan widgetni topadi. findsOneWidget β aynan bitta mos widget topilganini tekshiradi; findsNothing β hech qanday mos widget topilmaganini tekshiradi (masalan, biror narsa hali ko'rinmasligi kerakligini tasdiqlash uchun).
7. Bu qator mockga "agar harorat('Toshkent') chaqirilsa, asinxron ravishda 25 qaytar" deb o'rgatadi β haqiqiy hisob/tarmoqsiz, oldindan belgilangan javob. Mock ishlatish sabablari: (1) tezlik va ishonchlilik β haqiqiy tarmoq sekin va beqaror, mock esa darhol va doimo bir xil javob beradi; (2) boshqariluvchanlik β kerakli holatni (masalan xato yoki aniq qiymat) ataylab yaratib, sinaladigan kodni shu holatda tekshira olamiz; (yana: test tashqi serverga bog'liq bo'lmaydi).
8. Debug rejim (flutter run standart rejimi) ataylab sekin β u qo'shimcha tekshiruvlar, assertlar va optimallashtirilmagan kod bilan ishlaydi, shuning uchun uning tezligi haqiqiy emas. Unumdorlikni o'lchash uchun u flutter run --profile (profile rejimi) ishlatishi kerak edi β bu release'ga yaqin tezlikni beradi, lekin DevTools profillash asboblari yoqilgan. Profile rejimida DevTools Performance panelida UI va Raster oqimlarini ko'rib, haqiqiy jank manbasini topadi.
9. 1.2.0 β odamlarga ko'rinadigan versiya nomi (Android versionName, iOS marketing version). +5 β ichki build raqami (Android versionCode, iOS build number). Yangi release'da build raqami (+5) ni oshirish shart β chunki do'kon (Play Store/App Store) yangi nusxani eskisidan aynan shu raqam orqali ajratadi; agar u oshmasa, do'kon yangi yuklamani rad etadi. Versiya nomini (1.2.0) o'zgartirish foydalanuvchiga ko'rinadi, lekin majburiy emas.
10. key.properties parol va imzolash kaliti yo'lini saqlaydi β bu ilovangizni imzolaydigan maxfiy ma'lumot. U ochiq repozitoriyga tushsa, boshqalar sizning imzongiz bilan soxta yangilanish chiqarishi yoki ilovangizga taqlid qilishi mumkin β bu jiddiy xavfsizlik buzilishi. To'g'ri amaliyot: key.properties va keystore faylini .gitignore ga qo'shib, git'ga hech qachon qo'shmaslik; ularni alohida, xavfsiz joyda (parol menejeri, CI'ning maxfiy o'zgaruvchilari) saqlash. Agar tasodifan yuklangan bo'lsa β kalitni darhol yangi bilan almashtirish va sirlarni o'zgartirish kerak.
β¬ οΈ Oldingi: 28 β Platforma, paketlar va moslashuv Β· π README Β· Keyingi: 30 β Yakuniy loyiha: to'liq ilova β‘οΈ