Ja koliko znam, i u statički tipiziranom svetu pišu se unit testovi.
Na zalost pisu. To je upravo odlika onih koji ne znaju sta bi radili sa type sistemom i kojima je svejedno da li rade javascript, php, c++, C#, java, haskell, F# itd. Znas kako "funkcija je funkcija, petlja je petlja, if je if, nema tu mnogo razlike" filozofija :)
Digresija: prosle godine sam konkurisao za jednu firmu, remote work C#, dosta je ima na oglasima na SO, da je ne reklamiram, rekoh sebi da okusam srecu. Uglavnom, prvo dobijes pitanja pa zatim zadatak. Kada sam dobio zadatak, koji je manje vise bio neki mini web servis, dobio sam zahtev da se to lepo dokumentuje i napisu unit testovi, inace se ne prihvata kao validno resenje bez toga. Cim sam dobio zadak, samo sam im zahvalio i rekao da unit testove ne treba da radis u C#, tj u strongly typed jezicima i da neko ne razume bas najbolje C#. Nope, ne zelim da radim u startu sa takvima i govori mi u startu o kolicini njihovog znanja kao i filozovije (mogao bi se kladiti da je sledeca stvar na meniu DI :))
A ja još ne videh kako to kompajler rešava pitanje unit testova. Čime tačno zameniš ovo:
Ali zasto bi ih resavao. (samo da napomenem, primer koji si dao je skroz neadekvatan isto kao i onaj sa wikipedia, masi se skroz poenta). Zatim deo koji se testira je minoran i skoro pa nebitan u odnosu na ceo eco system. Type sistem ti nudi kompletnu drugu vrstu provere, ne ovu, ona koja je najmanja bitna, a to je lokalna funkcionalnost. Recimo, u C# ti moras bar jednom kada pises svoju f-ju da je proveris i svaki sledeci put kad je nesto menjas - to je jedini "a must". Sve ostalo ti type sistem garantuje. Nija stvar u tome da znas da funkcija lokalno dobro radi, nego da ona u celom ekosistemu ne remeti red.
Cak da uzmemo i ovaj primer sa dodavanjem, sta konkretno on demonstrira, tj. testira? Bez tipova to nekako jos deluje i da ima smisla, sa tipovima ne. Pricamo o konkretnom primeru, sto znaci da je ceo itnent da ti zelis garanciju da ces dobiti uvek broj sabiranjem dva broja. To je sve sto ja mogu da zakljucim. Definisanjem tipa, recimo u C#, ja znam da je ovaj slucaj zadovoljen i na dalje type sistem preuzima proveru code-a i nema ptrebe ja rucno da bilo sta kucam.
Recimo:
int Add(x, y) => x + y
class Control
{
int CalculateAbsoluteX(x) => Add(Control.Left + x)
int CalculateAbsoluteY(x) => Add(Control.Top + y)
}
Sta ces ti dobiti ako testiras Add funkciju? Apsolutno nista, imas garant type sistema da vraca integer. Ali, ako zato recimo promenis taj deo u:
double Add(x, y) => x + y
Type sistem ce ti se odma pobuniti i reci da si prekrsio contract u svim slucajevima. Kako to postizes testovima? Tako sto moras da pokrijes svaki poziv, svaku kombinaciju svih poziva funkcija i napises gomilu code-a koji opet nece biti precizan kao type sistem. I tu lezi ta moc, ne da testiras loklano, to radis dok razvijas, i dok god ispunjavas contract, dotle nema bojazni, a cak i kada prekrsis tu je type sistem da te podseti.
No, cak i ako ti to nije dovoljno i hoces da imas kroz staticku proveru, onda recimo imas Code Contracts. Njegov static checker ce ti upravo dati opciju da enforce-ujes constrainte sa vrednostima :)
Ako to nije dovoljno, mogao bi da napises svoj static checker koji ce da radi proveru :)
Ako i to nije dovoljno, mozes da automatizujes (tj. potencijalno je moglo) testove daleko bolje nego ti rucno da ih pises.
No samo da napomenem, meni svi ovi primeri nemaju smisla, svaki put kada vidim unit testove izgledaju ko cherry picking i osecam se ko budala koja ispunjava neki ritual :) Cak i kada sam na svom projektu pokusao da koristim Code Contracts, bas upravo zbog ovih stvari, verujuci da unit testovi imaju neki added value, zazalio sam. Kolicina noise koja se tako pravi je jednostavno ogromna naspram added value-a (koji je po mom misljenju skoro pa neprimetan).