{"id":7404,"date":"2011-08-08T12:30:18","date_gmt":"2011-08-08T10:30:18","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7404"},"modified":"2011-08-08T12:32:03","modified_gmt":"2011-08-08T10:32:03","slug":"uno-sguardo-a-unit-test-impariamo-a-prevenire-ore-e-ore-di-debug-durante-lo-sviluppo-di-applicazioni-ios","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/uno-sguardo-a-unit-test-impariamo-a-prevenire-ore-e-ore-di-debug-durante-lo-sviluppo-di-applicazioni-ios\/","title":{"rendered":"Uno sguardo a Unit test: impariamo a prevenire ore e ore di debug durante lo sviluppo di Applicazioni iOS"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/unit-test-xcode-devapp.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/unit-test-xcode-devapp.jpg\" alt=\"unit-test-xcode-devapp\" title=\"unit-test-xcode-devapp\" width=\"269\" height=\"248\" class=\"alignleft size-full wp-image-7447\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/unit-test-xcode-devapp.jpg 269w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/unit-test-xcode-devapp-150x138.jpg 150w\" sizes=\"auto, (max-width: 269px) 100vw, 269px\" \/><\/a> In questo articolo vedremo come effettuare un test del nostro codice sorgente utilizzando <strong>Unit Test<\/strong>. Per chi non ne fosse a conoscenza i test sono alla base di un modello di sviluppo chiamato, appunto, <strong>test-driven development<\/strong> e ne sono tanto alla base, che le procedure di test vengono scritte addirittura prima del codice da testare.<br \/>\nNon chiedetemi se sono favorevole a questo approccio; i miei brevi studi sulla calcolabilit\u00e0 e decidibilit\u00e0 mi fanno inorridire (e avrebbero fatto inorridire anche A.Turing (<a href=\"http:\/\/it.wikipedia.org\/wiki\/Alan_Turing\" target=\"_blank\">link<\/a>) all&#8217;idea di dimostrare il corretto funzionamento di un programma tramite un altro programma, ma se ridimensioniamo le aspettative e diciamo che i test non servono a <em>dimostrare<\/em> che un programma funzioni ma semplicemente per <em>verificare<\/em> che l&#8217;output prodotto a parit\u00e0 di input segua le nostre aspettative.. beh allora direi che tutto si fa pi\u00f9 interessante.<!--more--><\/p>\n<p>Per chi non avesse difficolt\u00e0 con l&#8217;inglese consiglio una lettura a <a href=\"http:\/\/developer.apple.com\/library\/ios\/#DOCUMENTATION\/Xcode\/Conceptual\/iphone_development\/135-Unit_Testing_Applications\/unit_testing_applications.html\" target=\"_blank\">questo articolo<\/a>: \u00e8 l&#8217;articolo dal quale ho preso spunto per scrivere questo testo che vi accingete a leggere. Tengo a precisare che la mia non vuole essere una semplice traduzione dell&#8217;articolo originale, ma reputo anche giusto sottolineare che non \u00e8 tutta farina del mio sacco e una citazione alla fonte sicuramente male non far\u00e0.<\/p>\n<p>Prima di addentrarci nel nostro articolo vediamo brevemente il significato di alcuni termini:<\/p>\n<ul>\n<li><strong>test case:<\/strong> Un singolo test usato per verificare una particolare funzionalit\u00e0 software.<\/li>\n<li><strong>test suite: <\/strong>Un insieme di test case che verificano il comportamento di una porzione pi\u00f9 ampia di codice.<\/li>\n<li><strong>logic tests:<\/strong> Sono i test che non vengono eseguiti all&#8217;interno di un&#8217;applicazione vera e propria. Si possono scrivere logic test e far s\u00ec che vengano eseguiti in fase di compilazione. Questo assicura al test una certa indipendenza dall&#8217;applicazione finale<\/li>\n<li><strong>application tests:<\/strong> Per convesso sono i test che vengono eseguiti all&#8217;interno di un&#8217;applicazione realmente funzionante. Sono eseguiti quindi a runtime non a compile-time. (non verranno presi in esame in questo articolo)<\/li>\n<\/ul>\n<h4>Come aggiungere un logic test al nostro software?<\/h4>\n<p>Xcode 4 prevede gi\u00e0 la possibilit\u00e0 di aggiungere, in fase di creazione del progetto, tutto quanto necessario per creare un unit test, ma per assicurarci una maggiore comprensione partiremo da un progetto vuoto.<\/p>\n<p>Creiamo quindi un nuovo progetto, io l&#8217;ho chiamato &#8220;TestOC&#8221;, perch\u00e9 il framework per effettuare i test si chiama &#8220;OCUnit&#8221;. Ok, ok&#8230; l&#8217;idea di inserire la parola &#8220;test&#8221; nel nome del progetto non \u00e8 stata proprio felicissima \ud83d\ude42<br \/>\nCreato il progetto bisogna aggiungere un nuovo <em>unit-test bundle target<\/em> e per farlo basta selezionare dentro Xcode l&#8217;icona del progetto e cliccare sul pulsante &#8220;Add target&#8221;  presente sulla destra. Selezioniamo quindi &#8220;Cocoa Touch Unit Testing Bundle&#8221; dalla schermata che appare e diamogli  un nome significativo.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target0.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target0-300x204.png\" alt=\"\" width=\"300\" height=\"204\" class=\"aligncenter size-medium wp-image-7411\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target0-300x204.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target0.png 742w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target1-300x204.png\" alt=\"\" width=\"300\" height=\"204\" class=\"aligncenter size-medium wp-image-7412\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target1-300x204.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target1-150x102.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Add_target1.png 742w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>A questo punto dovreste trovarvi con una struttura di file simile a questa:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/elenco_files.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/elenco_files.png\" alt=\"\" width=\"272\" height=\"271\" class=\"aligncenter size-full wp-image-7415\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/elenco_files.png 272w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/elenco_files-150x150.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/elenco_files-64x64.png 64w\" sizes=\"auto, (max-width: 272px) 100vw, 272px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>dove si pu\u00f2 notare che xCode ha gi\u00e0 creato per noi sia i file necessari per la compilazione, sia una classe &#8220;TestOCLogicTest&#8221; dove poter scrivere i nostri test.<\/p>\n<p>Se la vostra versione di xCode non dovesse aggiungere questa classe baster\u00e0 aggiungerla manualmente tramite la solita procedura &#8220;file -&gt; new-&gt;new file&#8221; selezionando il tipo &#8220;Objective-c Test case Class&#8221; e facendo attenzione di spuntare la casella solo per il target di testing.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/add_file.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/add_file-300x248.png\" alt=\"\" width=\"300\" height=\"248\" class=\"aligncenter size-medium wp-image-7416\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/add_file-300x248.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/add_file-150x124.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/add_file.png 543w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Se xcode ha creato per voi la classe &#8220;TestOCLogicTest&#8221; avr\u00e0 inserito all&#8217;interno una serie di metodi standard, per il momento commentateli ed aggiungete nel file .m questo codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void) testFail {\r\nSTFail(@\"Must fail to succeed.\");\r\n}\r\n<\/pre>\n<p>Selezionate lo schema appropriato usando il simulatore come device e cliccare sul pulsante &#8220;Test&#8221;, vedrete la vostra compilazione fallire miseramente con questo messaggio:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_fail.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_fail-300x152.png\" alt=\"\" width=\"300\" height=\"152\" class=\"aligncenter size-medium wp-image-7417\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_fail-300x152.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_fail-150x76.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_fail.png 485w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Cosa \u00e8 successo? Xcode ha effettuato il test del nostro codice, nello specifico ha eseguito il metodo &#8220;testFail&#8221; della classe &#8220;TestOCLogicTest&#8221; che ha come unico scopo quello di far fallire il test.<\/p>\n<p>Adesso facciamo un&#8217;altra prova e sostituiamo il metodo che abbiamo appena scritto con questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void) testPass {\r\nSTAssertTrue(TRUE, @\"\");\r\n}\r\n<\/pre>\n<p>Cosa succeder\u00e0 eseguendo il test? Apparentemente nulla, xcode dir\u00e0 &#8220;compilazione andata a buon fine&#8221; senza ulteriori dettagli, per\u00f2 se andiamo a guardare i messaggi di log nella console vedremo una serie di informazioni molto utili.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_success.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_success-300x85.png\" alt=\"\" width=\"300\" height=\"85\" class=\"aligncenter size-medium wp-image-7421\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_success-300x85.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_success-150x42.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/TestResult_success.png 535w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Se proprio siete curiosi potete provare ad inserire entrambi i metodi nella classe, noterete che vengono eseguiti tutti e due, indipendentemente dal loro ordine e sulla console viene mostrato un report di cosa \u00e8 successo:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/testResult_multiple.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/testResult_multiple-300x132.png\" alt=\"\" width=\"300\" height=\"132\" class=\"aligncenter size-medium wp-image-7423\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/testResult_multiple-300x132.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/testResult_multiple-150x66.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/testResult_multiple.png 537w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<h4>Scriviamo i nostri test<\/h4>\n<p>Ma cos&#8217;\u00e8 in soldoni un test? \u00c8 un metodo di istanza di una classe &#8220;SenTestCase&#8221; che non ha parametri, il suo nome inizia per test&#8230; e non ha nessun valore di ritorno. All&#8217;interno di questi metodi andremo and inizializzare i nostri oggetti e verificheremo se tutto \u00e8 andato a buon fine usando le Unit-Test macro. Chiaro, no?<\/p>\n<h4>Un caso concreto<\/h4>\n<p>Giusto per chi non avesse afferrato tutto tutto&#8230; descriviamo una situazione tipica:<br \/>\nAbbiamo creato una nostra classe (MyClass) che viene inizializzata prelevando alcuni valori da un file xml, ad esempio con un metodo simile a questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(id)initWithContentOfFile:(NSString *)filename {\r\nNSBundle *thisBundle = [NSBundle bundleForClass:[self class]];\r\nNSString *filePath = [thisBundle pathForResource:filename ofType:@\"plist\"];\r\n\t\r\nNSString *filePath = [[NSBundle mainBundle] pathForResource:filename ofType:@\"plist\"];\r\n\tNSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:filePath];\r\n\tif ([dict objectForKey:@\"Name\"]) {\r\n\t\tself = [super init];\r\n\t\tif (self) {\r\nself.name = [dict objectForKey:@\"Name\"]\r\n}\r\n\t}\r\n\telse {\r\nself = nil;\r\n\t}\r\n\treturn self;\r\n}\r\n<\/pre>\n<p>Benissimo, in questo modo siamo sicuri che la nostra classe sar\u00e0 consistente con l&#8217;idea che abbiamo  in testa.<\/p>\n<p>Facciamo adesso un balzo in avanti di qualche mese, avete assolutamente dimenticato questo aspetto un p\u00f2 particolare di questa classe e, visto che sono cambiate le specifiche, tra le altre 100 modiche fatte al codice qualcuno ha anche deciso di cambiare nel file plist la chiave che da &#8220;Name&#8221; \u00e8 diventata &#8220;Nome&#8221;&#8230; e ora <em>stranamente<\/em> il programma non funziona pi\u00f9&#8230;suona familiare? Quanto debug sar\u00e0 necessario prima di capire che la classe &#8220;MyClass&#8221; non pu\u00f2 essere istanziata con quel file plist e quindi risulta essere nil?<\/p>\n<h4>Risolviamo il nostro problema con unit test<\/h4>\n<p>Il programma non funziona perch\u00e9 sono venute meno le precondizioni che avevamo stabilito? Ma questo \u00e8 un lavoro per unit test! Quando abbiamo scritto per la prima volta il nostro metodo &#8220;initWithContentOfFile&#8221; avremmo potuto scrivere un test case per questo metodo, cos\u00ec adesso  che sono cambiate le precondizioni sicuramente il test ci avrebbe avvertito! Ma come creiamo quindi il test? Potremmo scrivere un test simile a questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)testCreationMyClassIstance {\r\nNSString *filename = @\"preferences\";\r\n\tMyClass *c = [[MyClass alloc] initWithContentOfFile:filename];\r\n\tSTAssertNotNil(c, @\"MyClass non \u00e8 stata inizializzata\");\r\n}\r\n<\/pre>\n<p>nel quale creiamo una istanza della classe &#8220;MyClass&#8221; e poi usiamo la macro &#8220;STAssertNotNil&#8221; per verificare che non sia nil.<\/p>\n<p>Se questo test viene eseguito prima  di fare la modifica al file plist vediamo che l&#8217;esito \u00e8 positivo:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.36.16.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.36.16-300x25.png\" alt=\"\" width=\"300\" height=\"25\" class=\"aligncenter size-medium wp-image-7424\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.36.16-300x25.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.36.16-150x12.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.36.16.png 591w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>mentre se invece effettuiamo maldestramente una modifica al file plist otteniamo immediatamente un comodissimo messaggio d&#8217;errore<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.38.00.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.38.00-300x45.png\" alt=\"\" width=\"300\" height=\"45\" class=\"aligncenter size-medium wp-image-7425\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.38.00-300x45.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.38.00-150x22.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/Screen-shot-2011-08-05-at-13.38.00.png 535w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Alla prossima!<br \/>\nIgnazioC<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In questo articolo vedremo come effettuare un test del nostro codice sorgente utilizzando Unit Test. Per chi&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[8],"tags":[869,871,241,866,872,242,867,868],"class_list":["post-7404","post","type-post","status-publish","format-standard","hentry","category-guide-varie","tag-cocoa-touch-unit-testing-bundle","tag-debug-xcode","tag-ignazio-calo","tag-ocunit","tag-sviluppo-applicazioni-iphone-e-ipad","tag-tutorial-xcode","tag-unit-test","tag-unit-test-bundle-target"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7404","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=7404"}],"version-history":[{"count":24,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7404\/revisions"}],"predecessor-version":[{"id":7450,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7404\/revisions\/7450"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7404"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7404"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7404"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}