Kā uzrakstīt labākus vienības testus iegulto programmatūru ar TDD

Fun with Music and Programming by Connor Harris and Stephen Krewson (Jūnijs 2019).

$config[ads_text] not found
Anonim

Kā uzrakstīt labākus vienības testus iegulto programmatūru ar TDD


Vēlaties izmēģināt vienības testēšanu jūsu iegulto programmatūru "// www.allaboutcircuits.com/technical-articles/unit-tests-can-help-you-write-better-embedded-software…-heres-how/" target = " _blank "> ieguvumus no vienības testēšanas sev, jums vajadzētu sākt ar testa virzītas attīstības (TDD).

Kas ir TDD?

Testa vadīta attīstība (TDD) ir atkārtojošs programmatūras ierakstīšanas process, kurā vienības pārbaudes tiek izstrādātas tieši pirms ieviešanas. Tā ir sašaurināta atsauksmju cilpa, kas sastāv no šādām darbībām:

  1. Uzrakstiet vienības testu, noskatīties, ka tas neizdodas.
  2. Uzrakstiet tikai pietiekami daudz kodu, lai nodotu testu.
  3. Uzlabojiet kodu (nemainot tā uzvedību).

Šīs darbības bieži tiek sauktas par "sarkanu, zaļu, refaktoru", jo pārbaude tiek veikta no neveiksmīgas (sarkanas) uz ietves (zaļas), ar galīgu iespēju uzlabot kodu un testus (refactor). Attīstības laikā šis cikls atkārtojas atkal un atkal simtiem vai tūkstošiem reižu.

Šajā procesā testu rakstīšana veicina programmatūras izstrādi. Jūs domājat par to, ko jūs vēlaties, lai kods tiktu darīts pirms tā rakstīšanas, un jūs ietaupāt šo ideju vienības testā. Tikai tad rakstāt nākamo koda bitu. Tas liek jums būt ļoti skaidram par to, ko vēlaties darīt.

Ar katru testu jūs izveidojat nedaudz vairāk pārliecības, ka jūsu programmatūra darbojas pareizi. Un, tā kā katrs koda kods tiek virzīts ar testu, jūs galu galā saņemat lielu testa segumu - jūsu koda daudzumu, kas tiek pārbaudīts, izmantojot vienības testus.

Netērējiet savu laiku, rakstot nekontrolējamu kodu

Viena no problēmām, kas saistītas ar vienības pārbaudēm - it īpaši, ja jūs vienkārši sākat darbu - ir tas, ka jūs varat beigties ar rakstīšanas kodu, ko ir grūti pārbaudīt.

Piemēram, varbūt jums ir kāda iekšējā stāvokļa, kas jums ir nepieciešama, taču jūs nevēlaties to pakļaut. Vai varbūt jūsu pārbaudāmajai vienībai ir daudz sarežģītu atkarību, kuras ir grūti izsmiet.

Testējamais rakstīšanas kods prasa pieredzi, bet kā jūs to varat iegūt? Nu, izrādās, ka jums nav nepieciešama šī pieredze, ja sākat ar TDD . Vispirms rakstot testus, jūs nevarat rakstīt nekontrolējamu kodu.

Jūs veiksies jau no paša sākuma, un tādēļ jūs, visticamāk, patiešām pieņemsiet vienības testēšanu kā praksi. Iedomājieties divus scenārijus:

1. scenārijs: jūs rakstāt visu ķekars kodu, tad jūs mēģināt izdomāt, kā to pārbaudīt. Ja jūs nevarat ātri to izdomāt, jūs atsakāties, jo jums ir programmatūra, ko piegādāt! Varbūt jūs uzzināt kaut ko par to, kā padarīt savu kodu vēl pārbaudāmāku nākamajā reizē.

2. scenārijs: jums ir ideja izveidot kādu programmatūras moduli, bet neesat pārliecināts, kā to pārbaudīt. Tātad jūs pavada nedaudz laika, uzzinot, kā rakstīt pirmo testu. Tad jūs uzrakstiet kādu kodu, lai to varētu nodot. Labi! Jūs tikko uzrakstījāt savu pirmo vienības testu. Jauki strādājat, tu kaut ko iemācījies. Atkārtojiet, kamēr jums ir pilnībā pārbaudīts vienības modulis. Apsveicam … tikko tik daudz uzzinājāt par vienības testēšanu.

TDD ir pieredzes pastiprinātājs . Jūs mācāties darot. TDD mudina jūs izdarīt pareizās lietas, lai jūs varētu uzzināt vairāk ātri. Jo vairāk jūs mācīties, jo labāk jūs saņemsit rakstot vienības testus.

Testa vadītais domāšanas veids

Kad jūs testē braukšanu, jūs domājat par rakstīto kodu mazliet savādāk. Tā vietā, lai mēģinātu sekot līdzi visam, ko vēlaties padarīt jūsu programmatūru, vienkārši jāuztraucas par nākamo lietu, ko vēlaties izmantot jūsu programmatūrai. Apskatīsim piemēru, kas ilustrē.

Viens no maniem iemīļotajiem TDD pārrunu piemēriem ir komandas parsētājs, jo tas tiek izmantots tik daudzās iegultās sistēmās. Bieži vien jūs vēlaties, lai jūsu sistēma spētu runāt ar ārpasauli, lai tā patiešām varētu veikt interesantas lietas. Tas varētu būt tikai vienkāršs seriālais interfeiss, ko izmanto konfigurēšanai, vai arī tas varētu būt savienojums ar citu ierīci vai varbūt Internets.

Pēc manas pieredzes, šāda veida saskarnes var patiešām izmantot vienības testēšanu. Tās parasti tiek izgatavotas pēc pasūtījuma, un to var ātri iegūt sarežģītā veidā - ar daudziem ceļiem caur kodu un daudzām kļūdu gadījumiem, kas jārisina. Un, tā kā šis ir sistēmas ārējais interfeiss, jūs ne vienmēr varat gaidīt, ka puisis no otras puses grasās izturēties labi. Tomēr ar dažām vienības pārbaudēm varat pārliecināties, ka viss darbojas kā paredzēts, un tiek apstrādāti visi kļūdu gadījumi.

Apsveriet iegulto sistēmu ar vienkāršu komandas parsētāju. Tas aizņem rakstzīmju straumi no kaut kur (varbūt sērijas vai USB, piemēram, bet mūsu parsētājs faktiski nav aprūpi), un dara kaut ko, ja ir saņemta īpaša rakstzīmju virkne. Šajā gadījumā sistēmā ir iebūvēts skaļrunis, ko var vadīt.

Lielākā iegulto programmatūras izstrādātāju instinkts būtu sākt rakstīt visu koda kodu komandā_parser.c. Testa vadītā pieeja ir atšķirīga.

Pirmais solis ir: rakstīt pārbaudi, noskatīties, ka tas neizdodas . Lai uzrakstītu testu, jums jāizrēķina pirmā lieta, ko vēlaties veikt komandas parsētājs. Ja ir protokola spec (ha, labi!), Jūs varat apskatīt to. Ja nē, jūs varat tieši izlemt, kas jums vispirms ir nepieciešams kods. Kā ar šo?

Kad ir saņemts "m" raksturs, tad skaļrunis ir izslēgts.

Labi, tas ir vienkāršs, mazs un skaidri definēts funkcionalitātes aspekts. Parādīsim vienības testu, kas tiktu nodots, ja kods tiktu ieviests.

 #include "some_test_framework.h" #include "some_mock_framework.h" #include "command_parser.h" #include "mock_speaker.h" // A test for the command_parser. void test_WhenAnMIsReceived_ThenTheSpeakerIsMuted(void) { // Receive an "m." command_parser_put_char('m'); // Make sure the mute function is called. EXPECT_CALL(speaker_mute()); } 

Viņš, tas ir tikai viens tests, bet šeit ir diezgan maz dizaina lēmumu.

Komandas parsētājs ir command_parser_put_char() jaunu funkciju: command_parser_put_char() . Tādā veidā rakstzīmes tiek ievadītas komandas parsētājs un kā "m" tiek nodots testā.

Ir arī cita jauna funkcija, kas ir definēta skaļruņa modulim: speaker_mute() . Tas ir tas, kas darīs faktisko runātāju izslēgšanu. Jūs zināt, ka tests ir pagājis, kad šī funkcija ir izsaukta.

Tā kā tas ir vienības tests, komandpparieris tiks pārbaudīts atsevišķi, un speaker_mute () reālā versija netiks izsaukta. Tā vietā tiks nodrošināta mock_speaker.h funkcija (iespējams, iekļauta mock_speaker.h ), un EXPECT_CALL makro ir stand- EXPECT_CALL jebkuram mocking mehānismam. Tas neizdosies testu, jo speaker_mute() funkcija netiek izsaukta.

Ņemiet vērā, ka neviena no šīm funkcijām vēl nav izveidota. Bet … jūs tikko definējāt precīzu rīcību, kuru vēlaties, un jums ir skaidrs veids, kā to pārbaudīt. Ja tev vajadzētu palaist testu, tas noteikti neizdosies. Faktiski tā netiks apkopota, jo funkcijas nepastāv.

Tagad otrajam solim: rakstīt tikai pietiekami daudz kodu, lai nodotu testu . Beidzot ir laiks rakstīt kādu kodu! Šeit ir vienkāršākais koda bits command_parser_put_char() lai veiktu pārbaudes pass:

 // Receive a character. void command_parser_put_char(char next_char) { speaker_mute(); } 

Ņemiet vērā, ka jums vajadzētu arī iestatīt savu izlikšanos speaker_mute() . Sīkāka informācija par to būs atkarīga no tā, kā jūs izmantojat savā projektā.

Testa rezultātam vajadzētu iet tagad … bet paziņojums, ka mēs pat nekontrolējam, kāds raksturs mēs saņēmām! Tas varētu šķist dīvains, bet viens no TDD mērķiem ir maksimāli palielināt darba apjomu, kas nav izdarīts .

Šobrīd tas ir mazsvarīgs piemērs. Ja kods kļūst sarežģītāks, tomēr jebkurš kods, kuru jūs faktiski neesat rakstījis, padarīs jūsu lietojumprogrammu vienkāršāku un vieglāk saprotamu (ahem .. labāk). Un, kad jūs veicat tikai tik daudz darba, cik nepieciešams, cilvēki, kas rūpējas par grafiku un budžetu, ir arī laimīgāki.

Pēdējais solis TDD ciklā ir refactor, kur jūs uzlabotu kodu, nemainot savu uzvedību . Šī solūta atslēga ir tā, ka jums jau ir vienības testi, kas apstiprina uzvedību. Tātad, jūs varat eksperimentēt ar koda maiņu, jo nepabeigtais tests tev tev uzreiz pateiks, ja mainījāt uzvedību. Tomēr, tā kā tas ir tikai pirmais tests, tomēr vēl nav daudz jāuzlabo.

Pārējo komandas parsētājs tiek īstenots, atkārtojot TDD ciklu. Tātad, ko jūs vēlaties, lai jūsu komanda parsētājs veiktu tālāk? Kā būtu:

Kad ir saņemts "u" raksturs, tad skaļrunis ir atslēgts.

Labi, tas ir vēl viens labs. Šeit ir pārbaude:

 void test_WhenAUIsReceived_ThenTheSpeakerIsUnmuted(void) { // When command_parser_put_char('u'); // Then EXPECT_CALL(speaker_unmute()); } 

Kad jūs uzlabojat komandas parsētājs ieviešanu, lai nokārtotu testu, tas var izskatīties šādi:

 void command_parser_put_char(char next_char) { if (next_char == 'm') { speaker_mute(); } else { speaker_unmute(); } } 

Kā rīkoties ar kļūdas gadījumu tagad? Ko darīt, ja tiek saņemts negaidīts raksturs?

Kad tiek saņemts negaidīts raksturs, tad skaļruņa izslēgšanas stāvoklis nemainās.

 void test_WhenAnUnexpectedCharIsReceived_ThenTheSpeakerMuteStateIsUnchanged(void) { // When command_parser_put_char('!'); // Then DO_NOT_EXPECT_CALL(speaker_mute()); DO_NOT_EXPECT_CALL(speaker_unmute()); } 

Un šeit ir tikai pietiekami daudz kodu, lai veiktu šo testa caurlaidi:

 void command_parser_put_char(char next_char) { if (next_char == 'm') { speaker_mute(); } else if (next_char == 'u') { speaker_unmute(); } } 

Vai šeit ir kaut kas, ko vēlaties pārveidot? Ja jūs vēlaties slēdzi paziņojumu, jūs varētu iet uz priekšu un mainīt to:

 void command_parser_put_char(char next_char) { switch(next_char) { case 'm': speaker_mute(); break; case 'u': speaker_unmute(); break; default: break; } } 

Hmm, vai šīs izmaiņas pārtrauca kaut ko? Nav sviedri, vienkārši palaidiet savus testus, lai uzzinātu.

No šejienes jūs vienkārši turpiniet darboties TDD ciklā - pievienojot testus un funkcionalitāti - līdz komandu analizētājs dara visu, kas jums to vajag.

Kā uzdevumu, uzskata, ka ir vēl viena komanda, kas ļauj iestatīt skaļuma līmeni. Varbūt "v", kam seko skaitlis. Kā jūs to uzrakstītu? Ar to tiks ieviesti arī jauni kļūdu gadījumi. Ko darīt, ja numurs nav derīgs? Ko darīt, ja jūs saņemat "v", pēc kura tūlīt seko "m"? Jūs varat redzēt, kā tas varētu ātri sarežģīt. Bet jūs varat uzrakstīt testu katram no šiem kļūdu gadījumiem! Katrā gadījumā jūs precīzi zināsiet, kā komandu parsētājs jāuzvedas - ja tas nenotiek, vienības testi ļaus jums to zināt.

Sarežģītu problēmu samazināšana vienkāršākos

Komandas parsētājs (vai jebkura programmatūras moduļa izveide) ir sarežģīts uzdevums. Ja jūs mēģināt iedomāties pabeigto moduli pirms pat sākuma, tas var būt grūti. Tas jo īpaši ir tas, ja jūs īstenojat kaut ko, ko nekad neesat darījis iepriekš, jo jums nav pieredzes, lai piemērotu dizaina modeļus. Cramming visu to jūsu smadzenes uzreiz rada augstu kognitīvo slodzi .

Bet testa vadītā pieeja var samazināt jūsu kognitīvo slodzi, atbrīvojot jūsu smadzenes, lai uzrakstītu kādu patiešām labu programmatūru. Apskatiet, ko mēs tikko darījām komandas parsētājs piemērā. Katrā posmā mēs rūpējāmies tikai par nākamo funkcionalitātes bitu, ko pievienot - ne visas funkcijas, kuras mēs varētu pievienot nākotnē. Atlikt visas šīs citas bažas vēlāk, ļauj koncentrēt visu mūsu uzmanību uz vienu lietu vienlaikus.

Instrumenti

Tātad TDD ir lieliski, vai ne? Viena no grūtībām ir tas, ka iegultā programmatūra (tas nozīmē, C) pārbaudes rīki nav tik lieliski. Kad jūs veicat TDD, jūs visu laiku izveidojat un veicat pārbaudes. Tas nozīmē, ka jums ir ļoti vienkārši pievienot jaunus testus un palaist tos. Ja šīs lietas ir grūti, jūs, iespējams, saņemat neapmierinātību un atmest.

Bet tas kļūst labāk. Līdzekļi, piemēram, Ceedling (ar Unity un CMock) var ātri piekļūt un darboties. Ceedling nodrošina automātisku testa atrašanu, izspēles radīšanu un testa izpildi, lai padarītu jūsu dzīvi vieglāku. Tāpēc es iesaku to ikvienam, kas ir jauns iegultā vienības testēšanā, un esmu īpaši rakstījis par to, kā lietot Ceedling, lai sāktu darbu ar TDD C.

TDD netiek plaši izmantots iegultajā programmatūrā. Ja jūs sākat eksperimentēt ar TDD, jūs gatavojaties uzstādīt iegultās programmatūras izstrādes malu (un par to varat runāt ar savu lietotni un web izstrādātāju draugiem!). Joprojām būs daudz ko iemācīties, bet jūs atradīsiet ceļu, lai uzlabotu sevi un savu kodu. Es domāju, ka jums patiks tas, ko atradīsit.