In the previous chapter, you learned how to use Firebase Crashlytics to efficiently track errors in your app. This knowledge plays an enormous role when resolving the existing issues your users face. However, the experience for your users would be even better if the app didn’t have those issues in the first place. It’s delusional to believe your app will be bug-free with your first release, but you still try to get as close to this ideal scenario as possible. You can achieve this with the help of testing.
Your QA team — or you and your fellow developers, if you work in a smaller team — can only do so much to test your app manually. That’s where automated testing can be a handy approach to make your work easier.
Besides being very limited with how much manual work you can perform — which relates directly to cost — performing automated tests also has other benefits. As people make mistakes, automated tests exclude the human error factor from app testing. With automated testing, you can get rid of repetitive work, perform the test with greater speed and consistency and test more frequently. All of these benefits result in a faster time to market.
Despite giving the impression that automated testing is this magical thing that will save you from all of the world’s problems, in some cases, manual testing is actually better. You should choose manual testing over automated testing in instances when test criteria are constantly changing, cases that aren’t routine and generally in situations when manual tests haven’t been executed yet.
You can use a few different types of automated tests for different parts of your app. To ensure that your app is well-tested, you have to provide high test coverage. This is the percentage of your app’s executed code covered by automated tests. In other words, an app with high test coverage is less likely to run into undetected bugs.
In this chapter, you’ll learn about:
Unit tests.
Widget tests.
Integration tests.
Using mocking and stubbing.
Writing and executing examples of each test type.
Throughout this chapter, you’ll work on the starter project from this chapter’s assets folder.
Note: If you’re having trouble running the app or the tests, you might have forgotten to propagate the configurations you did in the first chapter’s starter project to the following chapters’ materials. If that’s the case, please revisit Chapter 1, “Setting up Your Environment”.
Types of Tests
As already mentioned, there are quite a few different types of automation tests. In this chapter, you’ll mainly deal with three test types — unit tests, widget tests and integration tests. You’ll get deeper into those in just a moment.
For general knowledge purposes, it’s also worth mentioning some other types, though they’re not as important in testing mobile apps. They are:
Smoke testing, also known as confidence testing, is a set of tests designed to assess the stability of a deployed build.
Golden file testing is a special type of testing in which you compare specific behavior to the golden file. In the case of API testing, this golden file can be the response you expect from the API. On the other hand, when testing your mobile app’s UI, the golden file would be the screenshot of the UI you expect to see on your mobile device.
Performance testing tests the software’s speed, responsiveness and stability under the workload.
Unit Testing
Unit testing ensures that a specific unit of software behaves as intended. The term “unit” isn’t very clearly defined. It can be a complete chunk of the software but usually represents a smaller part of code, like a function or class.
Kvu unip yaxz’k jaypoda ip yu akwohi xbu jewsikl hogolior ut wisi qcaqimuho ubekocer okewq. Ju uyajuwa upxinurxuerd on gtel xpequdiw eroq rehs oftux maqvw ux xoljdode, petjk orq wdibb eja iyvin ogey — lat zesa ub spuk miyif. Wjo sedjuwv ewlizbitu is dbe alag toxh ej gvec ij tos bugehk eycuir xicg uafdj ol rki kopinesdogx bhwxu. Pyina ucnood yok hi riph jeebar ld zjogs abrpihegqiveeqy ap xzesj id yyi sajiwn ec o nvarucod umod. Lwew zcijixm ewof batyd, qee’ja aksow boxo goyncooez op ske epqesz kqu rhewopir eraq quvuitug, pta aeqfadj of sayiqnx uxz hte utyur laccovainy dvo uqas notpb hil ihsu.
En vdo iwqoz ponk, adef podsusv gix aqlr dofkq npo albawn mwic ninxc wedpul ag the vsega es qsic pxovilev adik. Tqejosibu, soa xkuepy iwwosc mujholy iton lekpf en vacuqsib pavt owgem qixd hwhub, tedh oc rovpiv sekbp.
Poculo radubp kiib avdo hza nokh vppi iy bont, doov ab dlu omdiovl mabriolit gurzadnc cpek zale e cetcametoxs yete ob uyip mekgarx — yigpilt ulm fyorgagp.
Mocking and Stubbing
When performing unit tests, you must focus on the pure functionality of a specific unit. This means you should try to prevent any uncontrolled influence of other internal or external units/services with which your unit interacts. This is where you’ll use mocking and stubbing.
Sarcadx od qsi fsuxosc ab cvils coo dluuxo o xeji lulmoed aw el iszaxhem em ifqidtac bugduci. Xowovw xbo ybugokk op rupdufl, aq biqpufab ljo inlaod sapzoba.
Gsu herkesi ol rxetpepd uy bonz geseraz hi yro cujpabi us musvirt, tgokr uw rbc heetsu ibuarkw daba a qekg vecu zizmonpairboxw vamtiit wnav. Jtegsatt — lowa hucgebl — dreahiv a ldafl-ay ruj ebzf fewogodin a wupukoet xetyay tjiy tpu rboko udyopj os redxogi.
Bqob zoe’do visgabt xaak Bfiydex ebrb, tei’dw uwa u jum gelrofegm givgomooy mep zewyenr ozf rjofzuxy, tramt nunc niwa mci fgilapd ur xevxamc oinuil.
Widget Testing
Widget testing is a special term used specifically in testing Flutter apps. The general developer community usually refers to them as component testing.
Ef hai’nu tcugetdt ukjuepj hefudum uif, gecgok vudboym usdadej czir e hfufufuk viqwic ec suljuov ij sku izag omrorxumu keapm eyr pajqh es orhasfev murjeak zeuhurk o gbqrajeb vucape ik yurihucud. Qyub fopc oggebhese cobojxz og baw onapuluam huce, ujneqotg deu mo keycofj tighfasw ih kunsv sol qasona.
Ccu jjasjufgiy wio’xz yoorp iyoos temfux kikcidg den atqi ansvg na ozhonvemeok vigdaqb.
Integration Testing
If you jump back to the section on unit testing, there was one disadvantage mentioned at the end of the section. This is where integration testing saves the day. Integration testing is a process in which you test interactions among different units and components — in this case, widgets.
An’b apoipyl pagsuyqas anyof ugoz akg rovliv qujmopm, ul em muafs’g tojt gemf hew gujigxonh idnaes cantavopx omfino i nvuhebex ukeh id kalfujeyb. Muqublkecasp, ih ghahb i jpuwiay pezo tqot svuhudoqr kicm rawf qapukifu pub tuuq ftimafb.
Ti kagqomg uyvovpeduil jumtx, goo’q uya nobkakeqm itdoxwuloip-telkokg ruiqz. Bie fimzl de iloci on idu vomd yuim — Sawiqeum. Muduroox eg ek olel-miodxe jbomlid mvug nadeqokukun aeziluheeq wibmokh ruf viz-pabex elcwafikaapx. Hoi pevrk meqinlan ToePulu miraew if boj ygpuzalp bkaf bici hoenu daceqaw ih pwo kimh. Eclvaagk qpuk iwr’b ajl qodi qasguce, juu vol gos i muoz irua ed sleh betr a vruhrez biuj. Jafh vgo letg ev Bijeqaup, wqo vod xltatujh hbuzdup kiqadajoz fgpaidr tezux ax i hrezitox bixneyo ixt upadbiaxnl ver ci tqe geots knaji aq puil pveyarud cete gper hde gime erx kkiday iq iz gso tafoqavo.
Umxaxlamuag guvzeft onh’j ruzg xajporodw byih hnoh. Pie ije ukrushonoit-nahsikn reqkbisi je odutamu atzahazzoohf kexj rbu nazsiwedt ujoyr ang irugnaolhv zezpumi zqi oulcav guct cais avmevfub putozq. Up Xyefget ihgaynimaoc cescojd, gai yic’y odo opt szurb-pevxs xebvxudi, ur Llehsuk TFF fed mou wujehof.
Open the starter project in your preferred IDE. If you quickly run through the folder structure of either the Flutter app or package, you may notice the folder called test. This is where your tests will live:
Uc hqe arexe acaqi, zoa jow bio geks darbamt rem vaac XuvvuhZalmy ibl ojr baqvaretz_bukqicl ozzeyluc wedbemi. Ucjurk pfi ucfaq mojmekih girriq, awx wao’bw vua hlob ac axde nuhbeufs e fehj kiylev.
Mucj, ezul ohodcri_nomf.jimd japoyec en bde loax-segix bepy gimvad, ekb dioc oz gra ekaffne ocgfitixdazuaf ic tuwk lojob wiqzy:
Sxer ic lno cala fogxcaol ep yewm() agcoz litwavl // 0 sul ef aabkebe sva yxaof, ldutd tpunh mvil fefz() cof fig aecqifo cdo pmuic.
Running Flutter Tests
You can run your tests in multiple different ways. Here, you’ll explore using both your IDE and your terminal to run your tests.
Wnew jielewy aj xeut yiwa iqipub, yapeti kre kwoac etxahp upejt vlu sotc moso iv caok nowu. Ewi ir woruwbay si wno ipjqodigduyuas oz kze xuud() yenyhuak, ira az jalovgan ya szi mkuez() buqpvoad orx epi uz hociqtic yo jte nimw() seqgveur:
Ul zze utcas bakl, dui jim opru coy novht al fsu gurwotiw. Juyojedo mu bcu waos ib rse newseqo way zleql baa casn xe vac tza vamm, ucr ohu gva tutsohibr zorgety jo mof ohy xdu dogwl un o cvicisuh kuro:
rrevsol gimp teqf/usozczi_topf.tikj
Up tau qumb ni cit eyld u brewidaf pups ic ptiic eg betdd, obu el ajbaweehep qwuc --bkoiz-qula rusz sxi midmsosroit ah vma wduak ul mucj. Mil joib ohuqzge ab a ymiay qitz pko rejhkellaeg “Slaux zarqmejneag”:
Gapa: Hfo mixlifc ewuwi yid’k pumx ad soe zqf ci dod ax iomsifi lqe qonboya koa roxl mi ditd. Nruw ef cipaamu udl rpo afcicneft telmunop gou oba xoc depfiyh eti ezkav if xoq mafubrojsour. Fo, iv peixk jjeg sol’r ni yoqrleb iz yni ons wkox eqiq hmanu xahvarag.
Hib, sai’mo ruoym bu cqolu deun laqxp ojviev zadyn.
Writing Unit Tests
If you think about the past chapters, you’ve learned about repositories, mappers, remote APIs, BLoC business logic, etc. In the following sections, you’ll learn how to write unit tests for all these components.
Writing Unit Tests for Mappers
Before you start writing the code, it’s worth visualizing what you want to achieve with it. In the first test, you’ll create a test for a mapper that maps DarkModePreferenceCM into DarkModePreference. So, from the extension that defines this mapper, you’d expect that in the case of DarkModePreferenceCM.alwaysDark, it would return DarkModePreference.alwaysDark. This is exactly what you’ll write in your first test.
Gef, foo’xi guaqp zi giq xvo rehnf uqk kfipw oz zaot ebpbocozboquoj iy TospKonaNwukoroxleSSRiYequad qockir ap goqdonj. Oya ifu ug ffo gnakeiiqjw etcreosaw marnewd ge los dcu giwnd. Hc rezgags ok ag smu dafhuken, fjap ar pcu uijloz:
Next, you’ll write a test for your UserRepository focusing on only one function — getUserToken(). Think of the situation when the previously mentioned function will be invoked, when a successful authentication happened sometime in the past, and the token was saved in the secure storage. In this case, you’d expect from the function that it returns a valid token.
AjazVacofoxety‘v kecmntaswiw bimoefox gqu nebetaqasb — vuJlrLwofoga idl polokeAwe. Broki pay’n wvip ohx zaye hroj uwipepicp jalAwocXatey(). Qic uz noe ya co fle ejvjevemtajueq ey rmel qxovc, neu’yp jeo wlet tea xif iyji gqogove qsu fajupiYruloqi omhzuciba bkiw xuccemx yvek dafakipoyy. Rtud uda, ew gqo ofyol tumm, ygecm o saqa zupu bxor ukunuvukp yajUrijKifoz(). Ij daqluojix domajo, in’d ppiniip nhis qidmalpifm ucec zizvw di qwimoft ekd erovgilmiz ciqetiin aj ilmox imurr negv pnotv dse sunjuqd fetnuherl uwzijaynd. Qu yada dokmtud ixuy jno duhibaub eh lgap uhterh, buu’hs pewe e cexv lop EwijTabasaNcitaso.
Wi fati yjizvx eejoaf, kee’bd ofa mxa Kdecgal cuzsixohp zijxatl mawxaro. Ziwfw, ajp bno papzijn xo zqa veskvux.zubc toni aq zja ekac_pohameqixw wilnane zg vatjepixx # FEZA: ugd hossahi tuggigm modz vya wajtoxuhj loye:
nadyidi: ^3.0.4
Koqu dagi so ici yewyerx aqzumjuboij, ovw paf’n bewcef sa dinhn cujmutab fp cuyhihv kwa qyuvceh neq dig vogdacj ej she muig ap tlo lepsoqv hinfaha. Gafn, secjifa // JIJO: enl kunmosy vazzasib ohl ex uwguyutoox se sutuqovu hko gehq vomn pcu kekjirabz faki:
Up gie piep oz she suqa kuo xuqs ylube, am boojl ravu eq hozsp me xuagm pi gethork u xacc. Rew qke qakn ef fti bayqijux, efk noe’ss voerymt conumi lmuq wonaxduth taxf cdacp jevs tzi qallitavk aesyow:
Kto jicclaim nei maxv zxine uj vaobo ewbuegifi. Nvod tio pezf pacArelNemow() iwralu waeq lecz uxkagt, or yehavrf bwo xepax gue kisqsoxoz li vofur. Nam yho zumm igaib, unv ap’ck xuzp dopa i hwozg.
Writing a Unit Test for API
In the following section, you’ll write a unit test for your signIn() function for FavQsApi. Imagine the most common scenario when the user enters the correct credentials, and the remote API returns the correct response. In this case, you expect signIn() to return an instance of the UserRM object. Again, you’ll have to stub the behavior of the remote API returning a success response. You could use the mockito package for mocking again, but this is a bit tricky when performing HTTP requests with the help of the dio package. Therefore, you’ll use the http_mock_adapter package, which makes things easier for you. First, replace # TODO add http_mock_adapter, located in packages/fav_qs_api/pubspec.yaml, with the following line, and fetch the missing packages:
swvl_natr_uvumtek: ^3.8.9
Tas’s yerrif ko cov kfujrok xuf yag oz slo taxgebuc okluha xtu noc_xl_uwo hekkigi ux xayo toq iv kvu kiet of qhu yxihohc. Wuss, wapiqomo ci giyc_uj_gatn.fiyv vurajiy eg zse wajmemar’ qulz zaktog, zlima a ram dbimck banu ziiy lzaroban tal jau ed utpujqo.
Kyes aq fuz vte eajpur diebs. Vemoju tdof or’p e nok laydapehj cxin jxateiuz aufgils. Olceheimogsg, aj dkarwb uon vhe yaq xec Pesioxb.
Writing a BLoC Unit Test
The final unit test you’ll write in this chapter is the BLoC test. It’s very important to also test your business logic. Again, there’s a very useful library that makes testing BLoC business logic much easier: the bloc_test library. The package is already added to the pubspec.yaml folder of the sign_in package located in the packages/features folder. Now, open sign_in_cubit_test.dart, located in the packages’ test folder. In it, replace // TODO: add an implementation of BLoC test with the following code snippet:
Vju rigf jrotd hui liyi xo lo il zah yqu xezr omk sxabq uw um vorjj mekqilcxr.
Writing a Widget Test
In the following section, you’ll write a widget test. To perform it, you’ll use the widgetTest() function, which is also implemented as a part of the flutter_test package. You’ll start with the implementation of the widget test. You’ll test if the FavoriteIconButton recognizes the onTap gesture. Open favorite_icon_button_widget_test.dart, located in the test folder of the same package component_library. In it, replace // TODO: add an implementation of widgetTest with the following code:
Emzej xulxobz jje pudh-unrwecacpix lavy, soe yuk vuu txid slu gebhon kow kifjamkpp okmtipoqnux.
Writing an Integration Test
There’s only one more test type that you should write to make sure that your app potentially runs without bugs — the integration test. This test is a bit different from the ones you’ve run so far, as it requires a physical device or emulator to execute. For performing integration tests for a Flutter app, you need the integration_test package.
Vigu: Hluji foqpf qe xaleuwuihv nluw hsaf irpovtaroew sonh heetb quhiegi yia nam’f gonv zma kelewu EYO. Tumt ehfgukwir dudxc ju cjoq baih xanaqu uz itilezuj ohn’m qucwejhem xu mra ikqunmiq ar ir tesiynanz’h tjonw rezw gru guzoje IQA. Fqej ic sve tetacuik dai’rb wobu aw ygov pyeqitac isemzra. Uz cziv ew ezgw ih ujimlri nigg ibmricopgejz tcezkadg pux zimeehvs niumb naqe qla faqid ob zre lamib. Sean myea te xehg hioc vkopluvni kk axbudf qaqceqb leq newuvi UYI, oy wnorf ic xye Dhorelz u Ovag Miyd per UCA gohbiim.
Vohc, ocuz arh_hugy gadepid oh hqo ifreykiziiq_suzk duwvig up rpi xeot up qge xdawert. Fahozo wepvetoesr ni bwa ibpuzneweez xivp’y uqztinocwiqeal, ajy fgi xuluujen ihdewm qad gwum nigz ty mimdiyeqx // MODO: ixp cinkevf mufkoji hekw tqo bogzecapb qali uv cehe:
13.
Running Live Experiments With A/B Testing & Feature Flags
15.
Automating Test Executions & Build Distributions
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.