Obsah
1. Testování Go aplikací s využitím knihovny GΩmega a frameworku Ginkgo
3. Testovaná funkce pro výpočet faktoriálu
4. Kostra jednotkových testů vytvořených s využitím knihovny Gomega
5. Alternativní způsob zápisu jednotkových testů
6. Porovnání numerických hodnot a použití klauzule SatisfyAll
7. Funkce pro výpočet faktoriálu vracející chybu
8. Rozšíření jednotkových testů o podmínku, zda došlo či naopak nedošlo k chybě
9. Zprávy vypsané ve chvíli, kdy je výpočet nekorektní
12. Příprava projektu pro otestování s využitím frameworku Ginkgo
13. Vygenerování kostry sady BDD testů
14. Vytvoření kostry BDD testu
16. Rozdělení složitějšího BDD testu do bloků
17. Podrobnější výpis průběhu testů
18. Chování frameworku Ginkgo při chybě
19. Repositář s demonstračními příklady
1. Testování Go aplikací s využitím knihovny GΩmega a frameworku Ginkgo
Již několik částí tohoto seriálu bylo věnováno problematice testování, ať již přímo psaní testů pro aplikace vyvinuté v jazyku Go (jednotkové testy, BDD), nebo použití Go pro testování REST API, testování aplikací s textovým uživatelským rozhraním atd. Tomuto důležitému tématu se budeme věnovat i dnes, protože si popíšeme velmi zajímavou knihovnu nazvanou GΩmega, kterou lze velmi snadno zkombinovat s frameworkem Ginkgo určeným pro tvorbu BDD testů.
Obrázek 1: Logo projektu GΩmega
2. Knihovna Gomega
Knihovna nazvaná Gomega nabízí programátorům velké množství takzvaných „matcherů“, což jsou – poněkud zjednodušeně řečeno – funkce kontrolující, jestli byla splněna nějaká podmínka. V případě, že podmínka splněna není, nahlásí se chyba, ovšem současně se vypíšou i přesné okolnosti, za jakých došlo k nesplnění podmínky. Jedná se o velmi užitečný mechanismus s vlastnostmi, kterých je v samotném jazyku Go (bez použití dalších knihoven) poměrně těžké dosáhnout, protože nejsou podporovány aserce a všechny podmínky je tak nutné zapisovat explicitně s využitím konstrukce if (což je ovšem informace, která se neobjeví ve výsledcích testů).
Podívejme se nyní, jaké „matchery“ v knihovně Omega nalezneme. U každého matcheru je napsána oblast, které se týká i stručný popis jeho činnosti:
Jméno | Oblast | Stručný popis |
---|---|---|
Equal | obecné hodnoty | základní kontrola – ekvivalence |
BeEquivalentTo | obecné hodnoty | test na ekvivalenci k zadané hodnotě |
BeIdenticalTo | obecné hodnoty | test na identitu |
BeAssignableToTypeOf | obecné hodnoty | test, zda je možné provést přiřazení |
BeNil | nulové hodnoty | test na hodnotu nil |
BeZero | nulové hodnoty | test na nulu |
BeTrue | pravdivostní hodnoty | test na hodnotu true |
BeFalse | pravdivostní hodnoty | test na hodnotu false |
HaveOccurred | chyby | test zda došlo k chybě |
Succeed | chyby | test zda nedošlo k chybě |
MatchError | chyby | test zda došlo k určité chybě |
Panic | chyby | test, zda se zavolala funkce panic |
BeClosed | kanály | kanál je uzavřen |
Receive | kanály | kanál přijal zadaný prvek |
BeSent | kanály | do kanálu byl odeslán zadaný prvek |
BeAnExistingFile | soubory | kontrola existence souboru |
BeARegularFile | soubory | kontrola existence běžného souboru (ne adresáře) |
BeADirectory | soubory | kontrola existence adresáře |
ContainSubstring | řetězce | test na existenci podřetězce |
HavePrefix | řetězce | test na existenci prefixu řetězce |
HaveSuffix | řetězce | test na existenci postfixu řetězce |
MatchRegexp | řetězce | test, jestli řetězec odpovídá regulárnímu výrazu |
MatchJSON | řetězce | dtto, ale pro řetězec obsahující reprezentaci JSONu |
MatchXML | řetězce | dtto, ale pro řetězec obsahující reprezentaci XML |
MatchYAML | řetězce | dtto, ale pro řetězec obsahující reprezentaci YAMLu |
HaveLen | kolekce | kolekce má zadanou velikost |
HaveCap | kolekce | kolekce má zadanou kapacitu |
ContainElement | kolekce | kolekce obsahuje element |
BeElementOf | kolekce | element je prvkem kolekce |
ConsistOf | kolekce | kolekce obsahuje |
HaveKey | kolekce | mapa má dvojici se zadaným klíčem |
HaveKeyWithValue | kolekce | mapa má dvojici se zadaným klíčem a hodnotou |
BeNumerically | číselné hodnoty | test na hodnotu bez ohledu na typ |
BeTemporally | číselné hodnoty | dtto, ale pro časové razítko |
And | spojky | splněny musí být všechny podmínky |
SatisfyAll | spojky | splněny musí být všechny podmínky |
Or | spojky | splněna musí být alespoň jedna podmínka |
SatisfyAny | spojky | splněna musí být alespoň jedna podmínka |
Not | spojky | logická negace podmínky |
3. Testovaná funkce pro výpočet faktoriálu
Několik demonstračních příkladů, které si dnes ukážeme, bude z důvodu stručnosti postaveno na testování klasické „školní“ funkce určené pro výpočet faktoriálu. Jeden z možných rekurzivních zápisů výpočtu faktoriálu může vypadat následovně:
package main func Factorial(n int64) int64 { switch { case n < 0: return 1 case n == 0: return 1 default: return n * Factorial(n-1) } }
V případě, že se jednotkové testy kontrolující činnost funkce Factorial vytváří pouze s využitím standardní knihovny testing, bude kód testů poměrně dlouhý, protože je nutné explicitně zapsat a otestovat všechny podmínky jen pomocí základních konstrukcí programovacího jazyka Go. Pokud nebudou testy založeny na tabulce, může jejich zápis vypadat následovně:
package main import ( "testing" ) func TestFactorialForZero(t *testing.T) { result := Factorial(0) if result != 1 { t.Errorf("Expected that 0! == 1, but got %d instead", result) } } func TestFactorialForOne(t *testing.T) { result := Factorial(1) if result != 1 { t.Errorf("Expected that 1! == 1, but got %d instead", result) } } func TestFactorialForSmallNumber(t *testing.T) { result := Factorial(5) if result <= 10 || result >= 10000 { t.Errorf("Expected that 5! == is between 10..10000") } } func TestFactorialForSmallNumberNegative(t *testing.T) { result := Factorial(20) if result <= 10 || result >= 10000 { t.Errorf("Expected that 20! == is between 10..10000") } } func TestFactorialForTen(t *testing.T) { result := Factorial(10) expected := int64(3628800) if result != expected { t.Errorf("Expected that 10! == %d, but got %d instead", expected, result) } } func TestFactorialForBigNumber(t *testing.T) { result := Factorial(20) if result <= 0 { t.Errorf("Expected that 20! > 0, but got negative number %d instead", result) } } func TestFactorialForEvenBiggerNumber(t *testing.T) { result := Factorial(30) if result <= 0 { t.Errorf("Expected that 30! > 0, but got negative number %d instead", result) } }
Výsledky takto naprogramovaných jednotkových testů získáme po spuštění příkazu:
$ go test -v
Zobrazit by se měly následující zprávy informující uživatele o průběhu celého testu:
=== RUN TestFactorialForZero --- PASS: TestFactorialForZero (0.00s) === RUN TestFactorialForOne --- PASS: TestFactorialForOne (0.00s) === RUN TestFactorialForSmallNumber --- PASS: TestFactorialForSmallNumber (0.00s) === RUN TestFactorialForSmallNumberNegative --- FAIL: TestFactorialForSmallNumberNegative (0.00s) factorial_test.go:31: Expected that 20! == is between 10..10000 === RUN TestFactorialForTen --- PASS: TestFactorialForTen (0.00s) === RUN TestFactorialForBigNumber --- PASS: TestFactorialForBigNumber (0.00s) === RUN TestFactorialForEvenBiggerNumber --- FAIL: TestFactorialForEvenBiggerNumber (0.00s) factorial_test.go:53: Expected that 30! > 0, but got negative number -8764578968847253504 instead FAIL exit status 1 FAIL _/home/tester/go-root/article_45/factorial1 0.005s
package main import ( "testing" ) type factorialEntry struct { n int64 expected int64 } func TestFactorial(t *testing.T) { var entries = []factorialEntry{ {0, 1}, {1, 1}, {2, 2}, {3, 6}, {9, 362880}, {10, 3628800}, {20, 2432902008176640000}, {-1, 1}, } for _, entry := range entries { computed := Factorial(entry.n) if computed != entry.expected { t.Errorf("%d! != %d, but %d", entry.n, computed, entry.expected) } else { t.Logf("factorial computer correctly for input %d", entry.n) } } }
S výsledky:
=== RUN TestFactorial --- PASS: TestFactorial (0.00s) factorial_2_test.go:28: factorial computer correctly for input 0 factorial_2_test.go:28: factorial computer correctly for input 1 factorial_2_test.go:28: factorial computer correctly for input 2 factorial_2_test.go:28: factorial computer correctly for input 3 factorial_2_test.go:28: factorial computer correctly for input 9 factorial_2_test.go:28: factorial computer correctly for input 10 factorial_2_test.go:28: factorial computer correctly for input 20 factorial_2_test.go:28: factorial computer correctly for input -1 PASS ok _/home/tester/temp/go-root/article_45/factorial1 0.004s
4. Kostra jednotkových testů vytvořených s využitím knihovny Gomega
Nyní si ukažme, jak by mohla vypadat kostra jednotkových testů v případě, že kromě standardní knihovny Testing použijeme i knihovnu Gomega. Nejdříve je nutné vytvořit strukturu představující instanci Gomega a předat jí ukazatel na strukturu typu testing.T:
g := NewGomegaWithT(t)
Následně již můžeme volat metody implementované touto strukturou a – což je v praxi mnohem důležitější a užitečnější – tyto metody zřetězit do podoby představující testovanou podmínku. Pokud tedy potřebujeme otestovat, zda se faktoriál vstupní hodnoty 0 rovná jedničce, musíme napsat:
g.Expect(Factorial(0)).To(Equal(int64(1)))
První tři testy na vstupní hodnoty 0, 1 a 10 lze zapsat takto:
package main import ( . "github.com/onsi/gomega" "testing" ) func TestFactorialForZero(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(0)).To(Equal(int64(1))) } func TestFactorialForOne(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(1)).To(Equal(int64(1))) } func TestFactorialForTen(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(10)).To(Equal(int64(3628800))) }
Výsledek běhu takto zapsaných testů získáme opět příkazem:
$ go test -v
Zde konkrétně:
=== RUN TestFactorialForZero --- PASS: TestFactorialForZero (0.00s) === RUN TestFactorialForOne --- PASS: TestFactorialForOne (0.00s) === RUN TestFactorialForTen --- PASS: TestFactorialForTen (0.00s) PASS ok factorial.go 0.005s
5. Alternativní způsob zápisu jednotkových testů
Alternativně je možné použít zápis, v němž se vyskytuje Unicode znak Ω (jméno funkce) a nepoužívá se objekt získaný voláním NewGomegaWithT:
package main import ( . "github.com/onsi/gomega" "testing" ) func TestFactorialForZero(t *testing.T) { RegisterTestingT(t) Ω(Factorial(0)).To(Equal(int64(1))) } func TestFactorialForOne(t *testing.T) { RegisterTestingT(t) Ω(Factorial(1)).To(Equal(int64(1))) } func TestFactorialForTen(t *testing.T) { RegisterTestingT(t) Ω(Factorial(10)).To(Equal(int64(3628800))) }
Výsledek běhu takto zapsaných testů by měl být shodný s předchozím příkladem:
=== RUN TestFactorialForZero --- PASS: TestFactorialForZero (0.00s) === RUN TestFactorialForOne --- PASS: TestFactorialForOne (0.00s) === RUN TestFactorialForTen --- PASS: TestFactorialForTen (0.00s) PASS ok factorial.go 0.006s
6. Porovnání numerických hodnot a použití klauzule SatisfyAll
Testy uvedené v předchozích dvou kapitolách sice byly zapsány korektně, ale měly několik nevýhod. Především se muselo provádět explicitní přetypování int na int64 a taktéž nebylo možné zapsat podmínky typu „je menší“, „je větší“ atd. Oba nedostatky lze vyřešit s využitím metody BeNumerically, které se předá jak testovaná relace (relační operátor zapsaný ve formě řetězce), tak i číselná hodnota. Případné konverze jsou provedeny zcela automaticky takovým způsobem, aby se skutečně porovnávaly hodnoty a nikoli i jejich typy:
g.Expect(Factorial(0)).To(BeNumerically("==", 1)) g.Expect(Factorial(5)).To(BeNumerically("<=", 10000))
Navíc je možné specifikovat, že některé podmínky musí být splněny současně. K tomuto účelu se používá klauzule SatisfyAll, kterou lze zkrátit na And, ovšem první jméno je v oblasti testů příhodnější. Můžeme tedy relativně snadno napsat test kontrolující, jestli se výsledek výpočtu faktoriálu nachází v nastavených mezích:
g.Expect(Factorial(5)).To(SatisfyAll(BeNumerically(">=", 10), BeNumerically("<=", 10000)))
Podívejme se nyní na upravené a rozšířené jednotkové testy kontrolující činnost funkce pro výpočet faktoriálu:
package main import ( . "github.com/onsi/gomega" "testing" ) func TestFactorialForZero(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(0)).To(BeNumerically("==", 1)) } func TestFactorialForOne(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(1)).To(BeNumerically("==", 1)) } func TestFactorialForTen(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(10)).To(BeNumerically("==", 3628800)) } func TestFactorialForSmallNumber(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(5)).To(SatisfyAll(BeNumerically(">=", 10), BeNumerically("<=", 10000))) }
Výsledky, které získáme po spuštění těchto testů:
=== RUN TestFactorialForZero --- PASS: TestFactorialForZero (0.00s) === RUN TestFactorialForOne --- PASS: TestFactorialForOne (0.00s) === RUN TestFactorialForTen --- PASS: TestFactorialForTen (0.00s) === RUN TestFactorialForSmallNumber --- PASS: TestFactorialForSmallNumber (0.00s) PASS ok factorial.go 0.006s
7. Funkce pro výpočet faktoriálu vracející chybu
Funkce pro výpočet faktoriálu, kterou jsme si ukázali ve třetí kapitole byla vytvořena ve stylu, který je očekáván u aplikací naprogramovaných například v jazyku C. Chybový stav je v případě potřeby signalizován speciální hodnotou. Pokud bychom například potřebovali signalizovat, že výpočet faktoriálu záporného čísla nelze vypočítat, mohla by se provést tato úprava:
func Factorial(n int64) int64 { switch { case n < 0: return -1 // speciální chybová hodnota case n == 0: return 1 default: return n * Factorial(n-1) } }
V tomto případě se ovšem nejedná o idiomatický kód programovacího jazyka Go. V Go je totiž dobrým zvykem, aby byla chyba signalizována skutečným objektem reprezentujícím chybu. Pokud funkce vrací hodnotu signalizující chybu, bývá tato hodnota vždy vrácena jako poslední. Výpočet faktoriálu tedy můžeme přepsat následovně (stále se jedná o školní příklad neaspirující na nejvyšší rychlost a nejnižší spotřebu operační paměti):
package main import "errors" func Factorial(n int64) (int64, error) { switch { case n < 0: return 0, errors.New("math: factorial of negative number?!?") case n == 0: return 1, nil default: ret, err := Factorial(n - 1) if err != nil { return 0, err } return n * ret, nil } }
8. Rozšíření jednotkových testů o podmínku, zda došlo či naopak nedošlo k chybě
Pro zjištění, zda testovaná funkce vrátila či nevrátila chybu, slouží klauzule HaveOccurred a Succed. Tyto klauzule se používají pouze společně s případnou chybovou hodnotou popř. hodnotou nil. Pokud pouze potřebujeme zjistit, že došlo k očekávané chybě (vrácení struktury reprezentující chybu), můžeme napsat:
_, err := Factorial(-1) g.Expect(err).Should(HaveOccurred())
Zápis opačné podmínky používá negovanou podmínku ShouldNot:
_, err := Factorial(0) g.Expect(err).ShouldNot(HaveOccurred())
V tomto případě ovšem bývá lepší zapsat podmínku bez negace:
_, err := Factorial(0) g.Expect(err).Should(Succeed())
Zajímavé je, že například výše popsaná podmínka BeNumerically je použitelná i ve chvíli, kdy porovnáváme dvě návratové hodnoty funkce – vlastní hodnotu faktoriálu a případnou informaci o chybě:
g.Expect(Factorial(10)).To(BeNumerically("==", 3628800)) g.Expect(Factorial(5)).To(SatisfyAll(BeNumerically(">=", 10), BeNumerically("<=", 10000)))
V tomto případě pochopitelně platí, že pokud funkce signalizuje chybu, bude to testem detekováno, a to i tehdy, pokud by první vrácená hodnota byla (čistě náhodou) korektní.
Podívejme se nyní na to, jakým způsobem lze rozšířit předchozí variantu jednotkových testů o další podmínky:
package main import ( . "github.com/onsi/gomega" "testing" ) func TestFactorialForNegativeValue(t *testing.T) { g := NewGomegaWithT(t) _, err := Factorial(-1) g.Expect(err).Should(HaveOccurred()) } func TestFactorialForZero(t *testing.T) { g := NewGomegaWithT(t) result, err := Factorial(0) g.Expect(err).ShouldNot(HaveOccurred()) g.Expect(result).To(BeNumerically("==", 1)) } func TestFactorialForOne(t *testing.T) { g := NewGomegaWithT(t) result, err := Factorial(0) g.Expect(err).Should(Succeed()) g.Expect(result).To(BeNumerically("==", 1)) } func TestFactorialForTen(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(10)).To(BeNumerically("==", 3628800)) } func TestFactorialForSmallNumber(t *testing.T) { g := NewGomegaWithT(t) g.Expect(Factorial(5)).To(SatisfyAll(BeNumerically(">=", 10), BeNumerically("<=", 10000))) }
Očekávané výsledky testů:
=== RUN TestFactorialForNegativeValue --- PASS: TestFactorialForNegativeValue (0.00s) === RUN TestFactorialForZero --- PASS: TestFactorialForZero (0.00s) === RUN TestFactorialForOne --- PASS: TestFactorialForOne (0.00s) === RUN TestFactorialForTen --- PASS: TestFactorialForTen (0.00s) === RUN TestFactorialForSmallNumber --- PASS: TestFactorialForSmallNumber (0.00s) PASS ok factorial.go 0.006s
9. Zprávy vypsané ve chvíli, kdy je výpočet nekorektní
Nyní si ukažme, jak se knihovna Gomega chová ve chvíli, kdy je výpočet faktoriálu naprogramován nekorektně, tedy tak, aby vracel chybné hodnoty. „Rozbití“ výpočtu lze samozřejmě provést mnoha různými způsoby, například špatně vypočtenou hodnotou pro rekurzivní výpočet:
package main import "errors" func Factorial(n int64) (int64, error) { switch { case n < 0: return 0, errors.New("math: factorial of negative number?!?") case n == 0: return 1, nil default: ret, err := Factorial(n - 2) if err != nil { return 0, err } return n * ret, nil } }
Spuštění testů podle očekávání povede k detekci chyby, ovšem zajímavější je sledovat, jaké informace se vypíšou. To je totiž velmi důležité – setkal jsem se již s mnoha projekty (vytvořenými v jiném programovacím jazyce), které při testování jen lakonicky vypíšou „assertion failed“ s již nedopsaným dodatkem „hledej Šmudlo“. Knihovna Gomega je ve chvíli, kdy dojde k chybě, velmi upovídaná, což je jen dobře (pokud naopak test projde bez chyby, nevypisuje se žádná dodatečná informace a to je taky správné chování):
=== RUN TestFactorialForNegativeValue --- PASS: TestFactorialForNegativeValue (0.00s) === RUN TestFactorialForZero --- PASS: TestFactorialForZero (0.00s) === RUN TestFactorialForOne --- PASS: TestFactorialForOne (0.00s) === RUN TestFactorialForTen --- FAIL: TestFactorialForTen (0.00s) factorial_test.go:30: Expected <int64>: 3840 to be == <int>: 3628800 === RUN TestFactorialForSmallNumber --- FAIL: TestFactorialForSmallNumber (0.00s) factorial_test.go:35: Unexpected non-nil/non-zero extra argument at index 1: <*errors.errorString>: &errors.errorString{s:"math: factorial of negative number?!?"} FAIL exit status 1 FAIL factorial.go 0.006s
10. Testování kolekcí – řezů a map
Podívejme se nyní ve stručnosti, jak lze testovat kolekce. Začneme řezem, u nějž lze otestovat jeho velikost (počet prvků), kapacitu a zda obsahuje zadaný prvek:
package main import ( . "github.com/onsi/gomega" "testing" ) func TestCollecions(t *testing.T) { g := NewGomegaWithT(t) c := []int{1, 2, 3, 4, 5} g.Expect(c).To(HaveLen(5)) g.Expect(c).To(HaveCap(5)) g.Expect(c).To(ContainElement(1)) g.Expect(c).To(Not(ContainElement(42))) }
Podobně můžeme testovat mapy (například výsledky nějaké funkce). Kromě výše uvedených testů je možné zjistit, zda mapa obsahuje nějaký specifikovaný klíč či nikoli:
package main import ( . "github.com/onsi/gomega" "testing" ) func TestCollecions(t *testing.T) { g := NewGomegaWithT(t) m := make(map[string]int) m["one"] = 1 m["two"] = 2 m["three"] = 3 g.Expect(m).To(HaveLen(3)) g.Expect(m).To(ContainElement(1)) g.Expect(m).To(Not(ContainElement(42))) g.Expect(m).To(HaveKey("two")) g.Expect(m).To(Not(HaveKey("fourty two"))) }
11. Framework Ginkgo
Ve druhé části dnešního článku se ve stručnosti seznámíme s frameworkem nazvaným Ginkgo, což je nástroj sloužící pro vytváření testů ve stylu BDD (Behavior Driven Development), tedy testů popisujících očekávané chování systému. Tento framework se velmi často kombinuje právě s knihovnou Gomega popsanou v předchozích kapitolách.
Obrázek 2: Logo frameworku Ginkgo
12. Příprava projektu pro otestování s využitím frameworku Ginkgo
Pro porovnání s předchozími demonstračními příklady budeme opět testovat funkci pro výpočet faktoriálu. Tentokrát ovšem bude tato funkce umístěna v balíčku nazvaném factorial:
package factorial func Factorial(n int64) int64 { switch { case n < 0: return 1 case n == 0: return 1 default: return n * Factorial(n-1) } }
Z balíčku, který se nyní skládá z jediného souboru, vytvoříme modul, a to konkrétně příkazem:
$ go mod init factorial
Po spuštění předchozího příkazu by měl vzniknout soubor nazvaný „go.mod“ s následujícím obsahem:
module factorial go 1.13
13. Vygenerování kostry sady BDD testů
Následně je nutné vytvořit kostru BDD testů. Ve skutečnosti je to velmi snadné, protože tuto práci za nás odvede přímo framework Ginkgo. Postačuje pouze použít příkaz:
$ ginkgo bootstrap
Po spuštění předchozího příkazu by měl vzniknout nový soubor nazvaný „factorial_suite_test.go“, jehož obsah je následující:
package factorial_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func TestFactorial(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Factorial Suite") }
Po prvním spuštění testů příkazem:
$ ginkgo
By mělo dojít k úpravě obsahu souboru go.mod:
module factorial go 1.13 require ( github.com/onsi/ginkgo v1.10.3 github.com/onsi/gomega v1.7.1 )
I souboru go.sum (povšimněte si mnoha závislostí):
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
14. Vytvoření kostry BDD testu
Následně je nutné vytvořit kostru BDD testu. K tomuto účelu slouží opět nástroj ginkgo, tentokrát ovšem s přepínačem generate, za nímž následuje jméno testu:
$ ginkgo generate factorial
Tento příkaz by měl vygenerovat soubor pojmenovaný „factorial_test.go“ s tímto obsahem:
package factorial_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "factorial" ) var _ = Describe("Factorial", func() { })
Tento test, i když ve skutečnosti neobsahuje žádné podmínky, můžeme po zakomentování nepoužitých importů spustit:
$ ginkgo Running Suite: Factorial Suite ============================== Random Seed: 1575486131 Will run 0 of 0 specs Ran 0 of 0 Specs in 0.000 seconds SUCCESS! -- 0 Passed | 0 Failed | 0 Pending | 0 Skipped PASS Ginkgo ran 1 suite in 670.848991ms
Obrázek 3: Barevná podoba výstupu.
15. Implementace BDD testu
Samotné kroky BDD testu se zapisují do volání funkce Describe, a to konkrétně ve tvaru vnořených anonymních funkcí. První anonymní funkce vytvoří kontext, v němž budou vybrané testy probíhat a jednotlivé konkrétní kroky jsou pak reprezentovány anonymní funkcí uvnitř It. Celek tak do značné míry připomíná Mocha framework ze světa JavaScriptu a TypeScriptu:
package factorial_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "factorial" ) var _ = Describe("Factorial", func() { Context("For zero input", func() { It("should be one", func() { Expect(Factorial(0)).To(Equal(int64(1))) }) }) })
Tento prozatím jednoduchý test můžeme opět spustit. Tentokrát by se měla vypsat informace o jednom úspěšně dokončeném testu:
$ ginkgo Running Suite: Factorial Suite ============================== Random Seed: 1575486467 Will run 1 of 1 specs • Ran 1 of 1 Specs in 0.000 seconds SUCCESS! -- 1 Passed | 0 Failed | 0 Pending | 0 Skipped PASS Ginkgo ran 1 suite in 710.057394ms Test Suite Passed
Obrázek 4: Barevná podoba výstupu.
16. Rozdělení složitějšího BDD testu do bloků
Rozsáhlejší testovací scénáře je vhodné rozdělit do několika bloků s odděleným kontextem. V našem konkrétním případě lze testovat výpočet faktoriálů negativních čísel, dále pak výpočet faktoriálu nuly a nakonec výpočet faktoriálu pro kladné vstupy:
package factorial_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "factorial" ) var _ = Describe("Factorial", func() { Context("For negative input", func() { It("should be one", func() { Expect(Factorial(-1)).To(Equal(int64(1))) Expect(Factorial(-10)).To(Equal(int64(1))) }) }) Context("For zero input", func() { It("should be one", func() { Expect(Factorial(0)).To(Equal(int64(1))) }) }) Context("For positive input", func() { It("should be n!", func() { Expect(Factorial(1)).To(Equal(int64(1))) Expect(Factorial(2)).To(Equal(int64(2))) Expect(Factorial(9)).To(Equal(int64(362880))) Expect(Factorial(10)).To(Equal(int64(3628800))) }) }) })
Výsledek takto strukturovaných testů:
$ ginkgo Running Suite: Factorial Suite ============================== Random Seed: 1575486790 Will run 3 of 3 specs ••• Ran 3 of 3 Specs in 0.000 seconds SUCCESS! -- 3 Passed | 0 Failed | 0 Pending | 0 Skipped PASS Ginkgo ran 1 suite in 697.181456ms Test Suite Passed
Obrázek 5: Barevná podoba výstupu.
17. Podrobnější výpis průběhu testů
V případě, že je zapotřebí vypsat podrobnější informace o probíhajících testech, lze použít přepínač -v (verbose) s následujícím účinkem:
Obrázek 6: Podrobnější výpis průběhu testů.
18. Chování frameworku Ginkgo při chybě
Pokud schválně poškodíme testovanou funkci tak, aby vracela nekorektní výsledky, dojde pochopitelně k detekci této anomálie přímo v testech:
package factorial func Factorial(n int64) int64 { switch { case n < 0: return 1 case n == 0: return 1 default: return n * Factorial(n-2) } }
V tomto případě Ginkgo společně s knihovnou Gomega ohlásí přesně, k jakému problému došlo a na jakém řádku testu:
$ ginkgo Running Suite: Factorial Suite ============================== Random Seed: 1575487214 Will run 3 of 3 specs •• ------------------------------ • Failure [0.000 seconds] Factorial /home/ptisnovs/src/go-root/article_45/iteration7/factorial_test.go:10 For positive input /home/ptisnovs/src/go-root/article_45/iteration7/factorial_test.go:22 should be n! [It] /home/ptisnovs/src/go-root/article_45/iteration7/factorial_test.go:23 Expected <int64>: 945 to equal <int64>: 362880 /home/ptisnovs/src/go-root/article_45/iteration7/factorial_test.go:26 ------------------------------ Summarizing 1 Failure: [Fail] Factorial For positive input [It] should be n! /home/ptisnovs/src/go-root/article_45/iteration7/factorial_test.go:26 Ran 3 of 3 Specs in 0.001 seconds FAIL! -- 2 Passed | 1 Failed | 0 Pending | 0 Skipped --- FAIL: TestFactorial (0.00s) FAIL Ginkgo ran 1 suite in 697.239929ms Test Suite Failed
Obrázek 7: Podrobnější výpis průběhu testů.
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně pět až šest megabajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
20. Odkazy na Internetu
- Ginkgo
http://onsi.github.io/ginkgo/ - Gomega
https://onsi.github.io/gomega/ - Ginkgo's Preferred Matcher Library na GitHubu
https://github.com/onsi/gomega/ - Provided Matchers
http://onsi.github.io/gomega/#provided-matchers - Dokumentace k balíčku goexpect
https://godoc.org/github.com/google/goexpect - Balíček goexpect
https://github.com/google/goexpect - Balíček go-expect
https://github.com/Netflix/go-expect - Balíček gexpect
https://github.com/ThomasRooney/gexpect - Expect (originál naprogramovaný v TCL)
https://core.tcl-lang.org/expect/index - Expect (Wikipedia)
https://en.wikipedia.org/wiki/Expect - Pexpect
https://pexpect.readthedocs.io/en/stable/ - Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
http://networkbit.ch/golang-ssh-client/ - goblin na GitHubu
https://github.com/franela/goblin - Mocha framework
https://mochajs.org/ - frisby na GitHubu
https://github.com/verdverm/frisby - package frisby
https://godoc.org/github.com/verdverm/frisby - Frisby alternatives and similar packages (generováno)
https://go.libhunt.com/frisby-alternatives - Cucumber for golang
https://github.com/DATA-DOG/godog - How to Use Godog for Behavior-driven Development in Go
https://semaphoreci.com/community/tutorials/how-to-use-godog-for-behavior-driven-development-in-go - Comparative Analysis Of GoLang Testing Frameworks
https://www.slideshare.net/DushyantBhalgami/comparative-analysis-of-golang-testing-frameworks - A Quick Guide to Testing in Golang
https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/ - Tom's Obvious, Minimal Language.
https://github.com/toml-lang/toml - xml.org
http://www.xml.org/ - Soubory .properties
https://en.wikipedia.org/wiki/.properties - Soubory INI
https://en.wikipedia.org/wiki/INI_file - JSON to YAML
https://www.json2yaml.com/ - Data Format Converter
https://toolkit.site/format.html - Viper na GitHubu
https://github.com/spf13/viper - GoDotEnv na GitHubu
https://github.com/joho/godotenv - The fantastic ORM library for Golang
http://gorm.io/ - Dokumentace k balíčku gorilla/mux
https://godoc.org/github.com/gorilla/mux - Gorilla web toolkitk
http://www.gorillatoolkit.org/ - Metric types
https://prometheus.io/docs/concepts/metric_types/ - Histograms with Prometheus: A Tale of Woe
http://linuxczar.net/blog/2017/06/15/prometheus-histogram-2/ - Why are Prometheus histograms cumulative?
https://www.robustperception.io/why-are-prometheus-histograms-cumulative - Histograms and summaries
https://prometheus.io/docs/practices/histograms/ - Instrumenting Golang server in 5 min
https://medium.com/@gsisimogang/instrumenting-golang-server-in-5-min-c1c32489add3 - Semantic Import Versioning in Go
https://www.aaronzhuo.com/semantic-import-versioning-in-go/ - Sémantické verzování
https://semver.org/ - Getting started with Go modules
https://medium.com/@fonseka.live/getting-started-with-go-modules-b3dac652066d - Create projects independent of $GOPATH using Go Modules
https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o - Anatomy of Modules in Go
https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 - Modules
https://github.com/golang/go/wiki/Modules - Go Modules Tutorial
https://tutorialedge.net/golang/go-modules-tutorial/ - Module support
https://golang.org/cmd/go/#hdr-Module_support - Go Lang: Memory Management and Garbage Collection
https://vikash1976.wordpress.com/2017/03/26/go-lang-memory-management-and-garbage-collection/ - Golang Internals, Part 4: Object Files and Function Metadata
https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - Go is on a Trajectory to Become the Next Enterprise Programming Language
https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 10 tools written in Go that every developer needs to know
https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 5 simple tips and tricks for writing unit tests in #golang
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - How the Go runtime implements maps efficiently (without generics)
https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/ - 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go