Typový system versus unittesty

v

Re:Typový system versus unittesty
« Odpověď #390 kdy: 26. 06. 2018, 08:38:28 »
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?


Kit

Re:Typový system versus unittesty
« Odpověď #391 kdy: 26. 06. 2018, 08:40:50 »
Rozumím. Ale chyba může vzniknout i při psaní testu. Vzhledem k tomu, jak často zoufale nečitelné mohou testy být - velmi snadno.
To je ovšem dané špatným způsobem psaní testů. Jednotkové testy mají testovat, zda pro „zajímavé“ vstupy dává kód očekávané výstupy. Není důvod, proč by takový test měl být nečitelný. V testu samozřejmě může být chyba, ale pak se na ní obvykle přijde při spouštění testů, protože test neprojde.

To je ten lepší případ. Horší je, když chybný test projde, což má BoneFlute zřejmě na mysli. Jenže pak nelze tvrdit, že tento test pokrývá testovaný kód - možná jen formálně.

Kit

Re:Typový system versus unittesty
« Odpověď #392 kdy: 26. 06. 2018, 08:46:29 »
Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
ale no tak... test může být prostě blbě - buď je chyba v něčem, co nekontroluje (např. testuje, že delete smaže prvek, ale nezkontroluje, že nesmaže víc než je požadováno) - 100% pokrytí splněno. Nebo máš testy, kdy se testuje, že pro zadaný vstup to dává furt stejný výstup...až na to, že ten "stejný" výstup je od začátku blbě. Opět klidně 100% pokrytí..

To je jen formálně 100% pokrytí, které spočítají nějaké automatické vyhodnocovače. To bych mohl napsat prázdné testy, které by nic nedělaly a také tvrdit, že mám 100% pokrytí. Ostatně totéž se běžně dělá i u typů, protože se s tím nikdo nechce piplat.
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?

Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.

Re:Typový system versus unittesty
« Odpověď #393 kdy: 26. 06. 2018, 09:04:16 »
Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
ale no tak... test může být prostě blbě - buď je chyba v něčem, co nekontroluje (např. testuje, že delete smaže prvek, ale nezkontroluje, že nesmaže víc než je požadováno) - 100% pokrytí splněno. Nebo máš testy, kdy se testuje, že pro zadaný vstup to dává furt stejný výstup...až na to, že ten "stejný" výstup je od začátku blbě. Opět klidně 100% pokrytí..

To je jen formálně 100% pokrytí, které spočítají nějaké automatické vyhodnocovače. To bych mohl napsat prázdné testy, které by nic nedělaly a také tvrdit, že mám 100% pokrytí. Ostatně totéž se běžně dělá i u typů, protože se s tím nikdo nechce piplat.
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?

Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.

Coz ti zadny nastroj jen tak neprozradi. Napovedet muze az mutacni testovani.

SB

Re:Typový system versus unittesty
« Odpověď #394 kdy: 26. 06. 2018, 09:17:29 »
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...

Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.


Kit

Re:Typový system versus unittesty
« Odpověď #395 kdy: 26. 06. 2018, 09:28:13 »
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...

Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.

Obvykle stačí testovat chování pro limitní a nadlimitní hodnoty vstupů. Testy tak vychází jen asi 2× delší než testovaný kód.

v

Re:Typový system versus unittesty
« Odpověď #396 kdy: 26. 06. 2018, 09:36:00 »
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...

Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.

Obvykle stačí testovat chování pro limitní a nadlimitní hodnoty vstupů. Testy tak vychází jen asi 2× delší než testovaný kód.
v dynamickém jazce? postněte nějaký jednoduchý příklad (funkce+testy), bylo by zajímavé zkusit co s tím udělá zavedení typů

Kit

Re:Typový system versus unittesty
« Odpověď #397 kdy: 26. 06. 2018, 09:47:01 »
Obvykle stačí testovat chování pro limitní a nadlimitní hodnoty vstupů. Testy tak vychází jen asi 2× delší než testovaný kód.
v dynamickém jazce? postněte nějaký jednoduchý příklad (funkce+testy), bylo by zajímavé zkusit co s tím udělá zavedení typů

Zavedení dalších typů s tím neudělá vůbec nic, protože typy nezkoumají funkčnost.

andy

Re:Typový system versus unittesty
« Odpověď #398 kdy: 26. 06. 2018, 09:52:57 »
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Pokud definuješ 100% pokrytí testy jako "kód pracuje správně", tak pak tvoje rada zní "pište programy správně"...

Obvyklá definice je ve stylu "testy spustí všechny řádky kódu programu". Ideální by byla definice ve stylu "testy projdou všechen stavový prostor", což ale vzhledem ke state-explosion je dost nereálné. Ale i to  negarantuje, že výsledný program bude pracovat správně (např. pro "a * b" by vstup "2,2" prošel veškerý stavový prostor, ale že jsi napsal "a + b" by neodhalil). Další možnost je projít všechny vstupy programu a porovnat je s očekávanými výstupy, ale to je v podstatě reimplementace toho programu, což ten problém moc neřeší...

Jinak když teda definuješ 100% pokrytí testy jako kód pracuje správně, jak bys definoval 90% pokrytí testy?

Kit

Re:Typový system versus unittesty
« Odpověď #399 kdy: 26. 06. 2018, 10:08:42 »
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Pokud definuješ 100% pokrytí testy jako "kód pracuje správně", tak pak tvoje rada zní "pište programy správně"...

Zajímavá implikace. Na to jsi přišel matematickými postupy?

Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.

Re:Typový system versus unittesty
« Odpověď #400 kdy: 26. 06. 2018, 10:09:34 »
Až na to, že pokud algoritmus něco složitého "počítá", tak není moc šance na to psát unit test buď tak, že ten algoritmus implementuje někdo jiný/jinak, nebo tak, že se prostě výsledek algoritmu vezme jako že je "správně". Ono to má své opodstatěnění, při refaktoringu/optimalizaci to najde, co to rozbilo (nebo naopak spravilo), ale bohužel chyby to často moc nemá šanci najít.
Jednotkový test nemá nic počítat. Když budu psát jednotkový test na odmocňování, budu testovat, že odmocnina ze dvou vrátí po zaokrouhlení 1,4142 (což si najdu třeba v tabulkách) a odmocnina z -2 vrátí chybu vstupu. Jak se ve skutečnosti odmocnina počítá nemusím pro psaní testu vůbec vědět. Ano, někdy je ten algoritmus tak netypický, že nikde jinde správné výsledky nenajdu, pak opravdu nezbývá, než testem zafixovat výsledky, co ten algoritmus spočítal. Ale to není tak častý případ.

No... taková trapárna jako "null pointer exception". Problém je, že u silného typového systému člověk prostě dělá design tak, aby k té chybě vůbec nemohlo dojít už z principu. U testů je velmi jednoduché zapomenout testovat nějakou funkci na to, zda při nějaké konfiguraci vstupů nespadne na null pointer exception.
„Null pointer exception“ je řekl bych ukázkový příklad. Můžu to ošetřit pomocí typů, pomocí assertů a nebo to můžu testovat. BoneFlute tu asserty řadí do typového systému a dospěl k tomu tak, že začal do typů vkládat přímo testy. Asserty jsou přitom záměrně navržené tak, aby jednoduché případy mohl vyhodnocovat už kompilátor (nebo něco k němu přilepeného). Takže dohadovat se, co přesně je ještě součástí kompilace a co už ne je trochu akademická diskuse, protože to záleží na konkrétní implementaci – právě asserty se obvykle vyhodnocují až za běhu (poprvé tedy typicky v testech), ale stejně tak je může vyhodnocovat už kompilátor.

Takže čistě z praktického hlediska u této konkrétní kategorie chyby bude typický výsledek ten, že typované programy prostě nullpointerexception vyhazovat nebudou, netypované "testované" ano, protože to programátor zapomněl na spoustě míst ošetřit a testy to nenašly.
Myslím, že je to opět spíš teoretický příklad. Z praktického hlediska bude k těm „null pointer exception“ docházet i v těch typových programech, protože ty nefungují ve vzduchoprázdnu, ale komunikují s okolím – a z něj ty NIL hodnoty dostávají. A i tam budou případy, kdy to programátor prostě přetypuje bez kontroly. Krásně je to vidět např. na Kotlinu, který nullable typy zavedl, ale když se někde váže na Javu, je to plné vykřičníků (tj. přetypování nullable typu na non-nullable, ze kterého může vypadnout NullPointerException).

Já to spíš vidím tak, že některé věci prostě není praktické psát do typů (navíc  u některých věcí neexistuje třeba jazyk, který by tyhle věci byl schopen vůbec vyjádřit, u souladu se specifikací to IMO u spousty věcí fakt nejde), někdy by z toho i tak bylo víc práce než užitku.... (na druhou stranu, prakticky kdykoliv jsem nepoužil NonEmpty pro neprázdný list, tak se mi to vymstilo).
Souhlasím. A stejně tak souhlasím s tím, že některé věci je naopak dobré mít v typech – třeba rozlišování typů na nullable/non-nullable považuju za hodně užitečné (i když to počet „null pointer exeception“ jen sníží, ale kromě akademických příkladů je nikdy nevymýtí úplně). Nikdy jsem netvrdil, že silnější typový systém nemůže některé testy učinit zbytečnými. Jenom tvrdím, že sebesilnější typový systém nedokáže nahradit všechny jednotkové testy – protože to, že se algoritmus pro nějaký vstup trefil do správného oboru hodnot ještě neznamená, že je výsledek správně.

Ale konkrétně - jak jsem se inspiroval tím LLVM paperem, tak jsem napsal interpret na ten Mapbox style jazyk a běželo to bez testů napoprvé (po cca. 5 hodinách psaní) a doteď jsem v tom kódu interpretu žádnou chybu nenašel (měl jsem jednu chybu mimo interpret, kdy jsem ve 3 ráno omylem napsal && místo ||). A tady je mimo jiné odpověď na týkající se otázky na "méně kódu" - díky těm typům pak při interpretaci není potřeba kontrolovat, jakého typu jsou vstupy funkcí. Protože prostě mají ten správný typ.
Tohle ale dobře funguje na nízké úrovni, v nějakých knihovnách (kde jsou zároveň nejsilnější i jednotkové testy). Jak se dostáváte výš, deklarativní popis typů by se začal komplikovat a srozumitelnější je použít asserty (i když osobně si myslím, že by programátor měl asserty považovat za deklaraci – ale pořád jsou to výrazy). A na ještě vyšších úrovních už se jenom propojují nějaké komponenty, tam už je řešení pomocí typů úplně nereálné (i kdyby jen proto, že ty komponenty vám dodává někdo jiný, koho nedonutíte detailně nadefinovat typy).

Re:Typový system versus unittesty
« Odpověď #401 kdy: 26. 06. 2018, 10:13:31 »
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
Ke slovesu pokrytí se váže předmět – tedy pokrytí čeho. Nemá smysl se tady dohadovat a neustále používat nevyjádřený předmět, když je zřejmé, že každý za předmět považuje něco jiného. Obvykle se „pokrytím testy“ myslí pokrytí kódu, tedy 100% pokrytí testy by znamenal pokrytí všech řádků/instrukcí. Které samozřejmě nezaručuje skoro nic, rozhodně nezaručuje bezchybnost. Vy asi myslíte 100% pokrytí všech možných případů, což je u jenom trošku větších věcí nedosažitelné.

andy

Re:Typový system versus unittesty
« Odpověď #402 kdy: 26. 06. 2018, 10:21:18 »
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Pokud definuješ 100% pokrytí testy jako "kód pracuje správně", tak pak tvoje rada zní "pište programy správně"...
Zajímavá implikace. Na to jsi přišel matematickými postupy?
Tak pokud bys někomu radil "mějte 100% pokrytí testy", tak vzhledem k tomu, že to definuješ jako program pracuje správně, tak jim radíš "pište programy, které pracují správně"...

Citace
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
To samozřejmě můžeš. Stejně jako to, že program používá nějaký typový systém neimplikuje, že program pracuje správně.

Re:Typový system versus unittesty
« Odpověď #403 kdy: 26. 06. 2018, 10:21:35 »
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...

Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.
To spolu ale nesouvisí. Testy mohou pokrývat 100 % kódu, tj. při spuštění testů se spustí všechny instrukce kódu. To ale vůbec neznamená, že by test duplikoval implementaci. Za „pokrytí testy“ se obvykle označuje právě poměr počtu instrukcí procházených při testech k celkovému počtu instrukcí knihovny či aplikace, protože to se dá změřit. To je reálné (i když to nemusí být nutné, protože chybějící testy mohou nepokrývat nezajímavé části kódu), ale v žádném případě to neříká, že by se testovaly všechny možné vstupy, nebo že by program byl bezchybný, pokud testy projdou. Ukazatel „pokrytí kódu/řádků/instrukcí testy“ má opačný význam – pokud určitá větev programu není testem pokrytá, víme určitě, že pomocí testů určitě nedokážeme poznat, zda v dané části chyba je nebo není.

netypová lopata

Re:Typový system versus unittesty
« Odpověď #404 kdy: 26. 06. 2018, 10:22:36 »
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.

100% pokrytí testy nelze dosáhnout ani teoreticky, protože Halting problem: https://en.wikipedia.org/wiki/Halting_problem

Doporučuju, Kite, nastudovat alespoň základy computer science, nebudeš se potom tady na fóru ztrapňovat tak často. A než začneš argumetovat tím, že je to jen teoretická konstrukce a nic takového, jako počítač s nekonečnou pamětí neexistuje, přečti si na wikipedii ten odstavec, který začíná The halting problem is theoretically decidable for linear bounded automata... a pochopíš, že to reálně opravdu udělat nejde.