Test yazmak, çoğu dilde sonradan öğrenilen bir konudur: Önce dili öğrenirsin, sonra bir test kütüphanesi seçersin, kurarsın, sözdizimini öğrenirsin. Go'da durum farklıdır. Test altyapısı dilin ve araç zincirinin bir parçasıdır: Ek bir kütüphane kurmadan, go test komutuyla çalışan, standart bir biçimi vardır. Bu yüzden Go projelerinde test yazmak bir "ekstra" değil, günlük çalışmanın doğal bir parçasıdır.
Go'nun test felsefesi de dilin geri kalanı gibi sadedir. Karmaşık iddia (assertion) kütüphaneleri, should/expect zincirleri ya da sihirli açıklayıcılar yoktur. Bir test, sıradan bir Go fonksiyonudur; beklenen ile gerçek değeri sen karşılaştırır, uyuşmazsa t.Errorf ile bildirirsin. İlk bakışta ilkel görünen bu yaklaşımın büyük bir avantajı vardır: Testi okuyan herkes, ne olduğunu anlamak için ayrı bir kütüphanenin belgesine bakmak zorunda kalmaz.
Bu derste test dosyalarının nasıl adlandırıldığını, t.Error ile t.Fatal arasındaki farkı, yardımcı fonksiyonların nasıl işaretlendiğini, Go'nun imzası hâline gelmiş tablo güdümlü testleri, alt testleri, performans ölçen benchmark'ları, belgeye dönüşen örnek fonksiyonlarını, kod kapsamını ve rastgele girdilerle hata arayan fuzzing'i öğreneceksin.
İlk test
Test dosyaları _test.go ile biter ve test ettikleri kodun yanında, aynı pakette durur. Test fonksiyonları Test ile başlar ve tek parametre alır:
package hesap
// Topla iki sayıyı toplar.
func Topla(a, b int) int { return a + b }
// Bol, b sıfırsa hata döndürür.
func Bol(a, b float64) (float64, error) {
if b == 0 {
return 0, ErrSifiraBolme
}
return a / b, nil
}package hesap
import "testing"
func TestTopla(t *testing.T) {
got := Topla(2, 3)
want := 5
if got != want {
t.Errorf("Topla(2, 3) = %d; beklenen %d", got, want)
}
}
func TestBolSifira(t *testing.T) {
_, err := Bol(1, 0)
if err == nil {
t.Fatal("sıfıra bölmede hata bekleniyordu, nil geldi")
}
}Testleri çalıştırmak için:
go test ./... # tüm paketlerin testleri
go test -v ./... # her testin adını ve sonucunu yazar
go test -run TestTopla # yalnızca adı eşleşen testler
go test -count=1 ./... # önbelleği atla, gerçekten çalıştırHata mesajının biçimi önemlidir. Go topluluğunda yerleşmiş kural şudur: ne çağrıldı, ne çıktı, ne bekleniyordu. t.Errorf("Topla(2, 3) = %d; beklenen %d", got, want) mesajı, test başarısız olduğunda kodu açmadan sorunu anlamanı sağlar. "test başarısız" gibi bir mesaj hiçbir işe yaramaz.
t.Error, t.Fatal ve t.Helper
Bir test başarısız olduğunda iki seçeneğin vardır:
t.Error/t.Errorftesti başarısız işaretler ama çalışmaya devam eder. Birbirinden bağımsız birkaç kontrol yapıyorsan hepsinin sonucunu tek çalıştırmada görmek istersin.t.Fatal/t.Fatalftesti başarısız işaretler ve hemen durdurur. Devam etmenin anlamsız olduğu durumlarda kullanılır: Bir nesne oluşturulamadıysa, sonraki satırlar zatennilüzerinde panikleyecektir.
Ortak kontrolleri bir yardımcı fonksiyona taşıdığında t.Helper() çağırmayı unutma. Bu çağrı, hata mesajındaki satır numarasının yardımcı fonksiyonu değil, çağıran satırı göstermesini sağlar:
package hesap
import "testing"
// requireNoError, hata varsa testi durdurur.
func requireNoError(t *testing.T, err error) {
t.Helper() // hata satır numarası çağıranı gösterir
if err != nil {
t.Fatalf("beklenmeyen hata: %v", err)
}
}
func assertEqual(t *testing.T, got, want float64) {
t.Helper()
if got != want {
t.Errorf("sonuç %v; beklenen %v", got, want)
}
}
func TestBol(t *testing.T) {
got, err := Bol(10, 4)
requireNoError(t, err)
assertEqual(t, got, 2.5)
}Testler varsayılan olarak aynı paket içinde sırayla çalışır. t.Parallel() çağıran testler ise birbirleriyle paralel çalışır; bu, yavaş testleri hızlandırır ama testler arasında paylaşılan durum varsa yarış durumlarına yol açar. Testlerini birbirinden bağımsız yazmak her zaman iyi bir fikirdir.
Test bittiğinde çalışacak temizlik kodunu t.Cleanup(func() { ... }) ile kaydedersin. defer'e benzer ama alt testlerde ve yardımcı fonksiyonlarda daha doğru davranır. Geçici dizin gerekiyorsa t.TempDir() hem dizini oluşturur hem test bitince siler.
Tablo güdümlü testler
Go'nun en karakteristik test biçimi budur: Test durumlarını bir dilimde toplar, tek bir döngüyle hepsini çalıştırırsın. Yeni bir durum eklemek tek satır alır.
func TestTopla(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"pozitifler", 2, 3, 5},
{"negatif ve pozitif", -4, 10, 6},
{"sıfırlar", 0, 0, 0},
{"büyük sayılar", 1_000_000, 2_000_000, 3_000_000},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { // alt test
if got := Topla(tt.a, tt.b); got != tt.want {
t.Errorf("Topla(%d, %d) = %d; beklenen %d", tt.a, tt.b, got, tt.want)
}
})
}
}t.Run her durumu ayrı bir alt test olarak çalıştırır. Bunun üç faydası vardır: Çıktıda hangi durumun başarısız olduğunu adıyla görürsün, tek bir durumu go test -run "TestTopla/sıfırlar" ile çalıştırabilirsin ve bir durumdaki t.Fatal diğerlerini engellemez.
Test durumlarına isim vermek zahmetli görünebilir ama vazgeçme: İsimsiz durumlarda hata mesajı yalnızca indeks verir ve hangi senaryonun bozulduğunu anlamak için sayarak ilerlemen gerekir.
Aşağıdaki program, tablo güdümlü test fikrinin nasıl çalıştığını testing paketi olmadan gösterir — böylece mantığı tarayıcıda da çalıştırabilirsin:
package main
import "fmt"
func Normalize(s string) string {
out := make([]rune, 0, len(s))
prevSpace := false
for _, r := range s {
if r == ' ' {
if prevSpace {
continue
}
prevSpace = true
} else {
prevSpace = false
}
out = append(out, r)
}
// baştaki ve sondaki boşlukları at
start, end := 0, len(out)
if end > 0 && out[0] == ' ' {
start = 1
}
if end > start && out[end-1] == ' ' {
end--
}
return string(out[start:end])
}
func main() {
tests := []struct {
name string
input string
want string
}{
{"boş", "", ""},
{"tek kelime", "go", "go"},
{"çoklu boşluk", "go hızlı dil", "go hızlı dil"},
{"kenar boşlukları", " merhaba ", "merhaba"},
}
failed := 0
for _, tt := range tests {
got := Normalize(tt.input)
status := "GEÇTİ"
if got != tt.want {
status = "KALDI"
failed++
}
fmt.Printf("%-18s %-6s %q → %q\n", tt.name, status, tt.input, got)
}
fmt.Println("başarısız:", failed)
}boş GEÇTİ "" → "" tek kelime GEÇTİ "go" → "go" çoklu boşluk GEÇTİ "go hızlı dil" → "go hızlı dil" kenar boşlukları GEÇTİ " merhaba " → "merhaba" başarısız: 0
Benchmark yazmak
Benchmark fonksiyonları Benchmark ile başlar ve *testing.B alır. Go 1.24 ile gelen b.Loop() yazımı, eski for i := 0; i < b.N; i++ kalıbının yerini aldı ve derleyicinin ölçülen kodu yanlışlıkla eleme riskini ortadan kaldırdı:
package hesap
import (
"strings"
"testing"
)
func BenchmarkConcat(b *testing.B) {
words := []string{"go", "hızlı", "basit", "güçlü"}
for b.Loop() {
s := ""
for _, w := range words {
s += w + " " // her adımda yeni string ayırır
}
_ = s
}
}
func BenchmarkBuilder(b *testing.B) {
words := []string{"go", "hızlı", "basit", "güçlü"}
for b.Loop() {
var sb strings.Builder
for _, w := range words {
sb.WriteString(w)
sb.WriteString(" ")
}
_ = sb.String()
}
}Çalıştırmak için:
go test -bench=. -benchmem ./...Çıktı şuna benzer:
BenchmarkConcat-8 8123456 142.3 ns/op 112 B/op 3 allocs/op
BenchmarkBuilder-8 19876543 61.5 ns/op 48 B/op 2 allocs/opSütunlar sırasıyla: yineleme sayısı, yineleme başına süre, yineleme başına ayrılan bellek ve ayırma sayısı. -benchmem bayrağı son iki sütunu ekler ve çoğu zaman süreden daha öğreticidir: Bellek ayırma sayısını düşürmek, performans iyileştirmelerinin en verimli yoludur.
Example fonksiyonları
Example ile başlayan fonksiyonlar hem belge hem testtir. Gövdenin sonundaki // Output: yorumu beklenen çıktıyı belirtir; go test bunu gerçek çıktıyla karşılaştırır. Böylece belgelerdeki örnekler asla eskimez:
package hesap_test
import "fmt"
func ExampleTopla() {
fmt.Println(Topla(2, 3))
// Output: 5
}
func ExampleBol_sifira() {
_, err := Bol(1, 0)
fmt.Println(err)
// Output: sıfıra bölme
}Adlandırma kuralı anlamlıdır: ExampleTopla, Topla fonksiyonunun belgesinde görünür; ExampleBol_sifira ise Bol'un belgesinde "sifira" başlıklı ek bir örnek olarak listelenir. Çıktı sırası belirsizse // Unordered output: kullanılır.
Kapsama (coverage)
Kod kapsama, testlerin kodun hangi satırlarını çalıştırdığını ölçer:
go test -cover ./... # yüzdeyi yazar
go test -coverprofile=cover.out ./... # ayrıntılı profil üretir
go tool cover -html=cover.out # tarayıcıda renkli rapor açar
go tool cover -func=cover.out # fonksiyon bazında yüzdelerKapsama sayısını bir hedef hâline getirmek yaygın bir hatadır. Yüzde yüz kapsama, kodun doğru olduğunu kanıtlamaz: Her satırı çalıştıran ama hiçbir şeyi doğrulamayan testler yazmak mümkündür. Kapsama raporunun asıl değeri, hiç dokunulmamış bölgeleri göstermesidir. Kırmızı kalan bir hata yolu genellikle "bu durumu hiç düşünmedik" demektir ve bakmaya değer.
Fuzzing
Fuzz testleri, fonksiyonuna rastgele üretilmiş girdiler vererek çökme veya beklenmeyen davranış arar. Go'nun fuzzing desteği araç zincirine gömülüdür:
package metin
import (
"testing"
"unicode/utf8"
)
func FuzzTersCevir(f *testing.F) {
// Tohum (seed) girdileri: bilinen ilginç durumlar
f.Add("merhaba")
f.Add("")
f.Add("çğışöü")
f.Fuzz(func(t *testing.T, s string) {
if !utf8.ValidString(s) {
t.Skip() // geçersiz UTF-8 bu fonksiyonun sözleşmesi dışında
}
rev := TersCevir(s)
if !utf8.ValidString(rev) {
t.Errorf("%q ters çevrildi ve geçersiz UTF-8 üretti: %q", s, rev)
}
if TersCevir(rev) != s { // iki kez ters çevirmek özgün metni vermeli
t.Errorf("çift ters çevirme %q yerine %q verdi", s, TersCevir(rev))
}
})
}go test -fuzz=FuzzTersCevir -fuzztime=30sFuzzing'in gücü, değişmezleri (invariant) sınamasından gelir. Yukarıdaki testte iki değişmez var: Çıktı geçerli UTF-8 olmalı ve iki kez ters çevirmek özgün metni geri vermeli. Bu tür özellikleri doğrulamak, tek tek örnek girdiler yazmaktan çok daha güçlüdür — çünkü fuzzer, senin aklına gelmeyecek girdileri bulur. Bir çökme bulduğunda onu testdata/fuzz/ altına kaydeder ve o girdi bundan sonra normal bir test durumu olarak çalışır.
İyi test yazmanın ilkeleri
Test altyapısını öğrenmek bir günlük iştir; iyi test yazmayı öğrenmek yıllar alır. Aşağıdaki ilkeler, kod incelemelerinde en sık tekrarlanan geri bildirimlerin özetidir.
Davranışı test et, uygulamayı değil. İç ayrıntılara bağlanan testler, kodu her yeniden düzenlediğinde kırılır ve zamanla insanları test yazmaktan soğutur. Dışarıdan gözlenebilen davranışa odaklan: Verilen girdiye karşılık ne dönüyor, hangi yan etki oluşuyor?
Her testin tek bir sebebi olsun. Bir test başarısız olduğunda, nedenini düşünmeden anlayabiliyor olmalısın. Onlarca iddiayı tek bir teste doldurmak, hata mesajını okunmaz hâle getirir.
Sınır durumlarını yaz. Boş girdi, tek elemanlı girdi, en büyük değer, negatif sayı, geçersiz kodlama, eşzamanlı erişim. Hataların çoğu tam olarak bu kenarlarda yaşar; ortadaki mutlu yol zaten elle de denenmiştir.
Testleri birbirinden bağımsız tut. Bir testin diğerinin bıraktığı duruma bağlı olması, sıra değiştiğinde ya da paralel çalıştırıldığında açıklanamayan hatalar üretir. Ortak kurulum gerekiyorsa her testin kendi kopyasını almasını sağla.
Zamanı ve rastgeleliği dışarıdan ver. Şimdiki zamanı doğrudan okuyan ya da kendi rastgele sayısını üreten kod test edilemez. Bu bağımlılıkları parametre olarak alırsan, testte sabit bir değer geçirip sonucu kesin biçimde doğrulayabilirsin.
Hata yollarını da test et. Çoğu kod tabanında mutlu yol iyi test edilmiştir; asıl sürprizler hata dallarında çıkar. Bir fonksiyon hata döndürebiliyorsa, o hatanın gerçekten döndüğünü ve doğru bilgiyi taşıdığını sına.
Sık yapılan hatalar
- Belirsiz hata mesajları yazmak. Mesaj ne çağrıldığını, ne çıktığını ve ne beklendiğini söylemeli.
t.Fatal'ı yardımcı fonksiyondat.Helper()olmadan kullanmak. Hata satırı yardımcıyı gösterir, sorunu bulmak zorlaşır.- Test durumlarına isim vermemek. Hangi senaryonun kaldığını anlamak zorlaşır.
- Kapsamayı hedef hâline getirmek. Yüzde yüz kapsama doğruluk kanıtı değildir.
- Testleri paylaşılan duruma bağlamak. Sıra değişince ya da paralel çalışınca kırılırlar.
- Zamanı ve rastgeleliği kodun içinden okumak. Test edilemez kod üretir.
- Benchmark sonucunu tek çalıştırmadan yorumlamak. Gürültüyü gerçek fark sanırsın.
go testönbelleğini unutmak. Değişmemiş testler yeniden çalışmaz; zorlamak için-count=1kullan.
Alıştırmalar
Bir e-posta adresinin biçimsel olarak geçerli sayılıp sayılmayacağını basitçe kontrol eden bir fonksiyon yaz (tek bir @ içermeli, @ işaretinin iki yanı da boş olmamalı, alan adında en az bir nokta bulunmalı). Ardından tablo güdümlü bir sınama döngüsüyle en az altı durumu test et ve sonucu raporla.
İpucu
strings.Count, strings.Index ve strings.Contains bu kontrol için yeterli. Sınır durumlarını unutma: boş metin, birden çok @, noktasız alan adı.
Çözümü göster
package main
import (
"fmt"
"strings"
)
func ValidEmail(s string) bool {
if strings.Count(s, "@") != 1 {
return false
}
at := strings.Index(s, "@")
local, domain := s[:at], s[at+1:]
if local == "" || domain == "" {
return false
}
if !strings.Contains(domain, ".") {
return false
}
if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") {
return false
}
return true
}
func main() {
tests := []struct {
name string
input string
want bool
}{
{"geçerli", "[email protected]", true},
{"boş", "", false},
{"at yok", "ali.example.com", false},
{"iki at", "ali@@example.com", false},
{"yerel boş", "@example.com", false},
{"noktasız alan", "ali@example", false},
{"nokta ile biten", "ali@example.", false},
{"alt alan adı", "[email protected]", true},
}
failed := 0
for _, tt := range tests {
got := ValidEmail(tt.input)
mark := "✓"
if got != tt.want {
mark = "✗"
failed++
}
fmt.Printf("%s %-16s %-24q got=%-5t want=%t\n", mark, tt.name, tt.input, got, tt.want)
}
fmt.Println("başarısız durum sayısı:", failed)
}✓ geçerli "[email protected]" got=true want=true ✓ boş "" got=false want=false ✓ at yok "ali.example.com" got=false want=false ✓ iki at "ali@@example.com" got=false want=false ✓ yerel boş "@example.com" got=false want=false ✓ noktasız alan "ali@example" got=false want=false ✓ nokta ile biten "ali@example." got=false want=false ✓ alt alan adı "[email protected]" got=true want=true başarısız durum sayısı: 0
Gerçek bir test dosyasında bu döngü t.Run(tt.name, ...) içinde çalışır ve karşılaştırma başarısız olduğunda t.Errorf çağrılır. Burada testing paketi kullanamadığımız için aynı yapıyı elle kurduk; mantık birebir aynıdır.
Bir aboneliğin süresinin dolup dolmadığını söyleyen bir fonksiyon yaz. Şimdiki zamanı fonksiyonun içinden okumak yerine parametre olarak al ve böylece testte sabit bir tarih geçirebildiğini göster. Farklı tarihlerle en az dört durumu sına.
İpucu
time.Time değerlerini time.Date(...) ile sabit olarak oluşturabilirsin. Karşılaştırma için Before ve After metotlarını kullan.
Çözümü göster
package main
import (
"fmt"
"time"
)
type Subscription struct {
Plan string
Expires time.Time
}
// IsActive, aboneliğin verilen ana göre etkin olup olmadığını söyler.
// Şimdiki zaman parametre olarak alındığı için fonksiyon tamamen test edilebilir.
func (s Subscription) IsActive(now time.Time) bool {
return now.Before(s.Expires)
}
// DaysLeft, kalan tam gün sayısını verir; süresi dolmuşsa 0 döner.
func (s Subscription) DaysLeft(now time.Time) int {
if !s.IsActive(now) {
return 0
}
return int(s.Expires.Sub(now).Hours() / 24)
}
func main() {
expiry := time.Date(2026, time.March, 15, 12, 0, 0, 0, time.UTC)
sub := Subscription{Plan: "yıllık", Expires: expiry}
tests := []struct {
name string
now time.Time
want bool
}{
{"bir ay önce", time.Date(2026, time.February, 15, 12, 0, 0, 0, time.UTC), true},
{"bir gün önce", time.Date(2026, time.March, 14, 12, 0, 0, 0, time.UTC), true},
{"tam bitiş anı", expiry, false},
{"bir saat sonra", expiry.Add(time.Hour), false},
}
for _, tt := range tests {
got := sub.IsActive(tt.now)
fmt.Printf("%-16s aktif=%-6t beklenen=%-6t kalan gün=%d\n",
tt.name, got, tt.want, sub.DaysLeft(tt.now))
}
}bir ay önce aktif=true beklenen=true kalan gün=28 bir gün önce aktif=true beklenen=true kalan gün=1 tam bitiş anı aktif=false beklenen=false kalan gün=0 bir saat sonra aktif=false beklenen=false kalan gün=0
Bağımlılığı dışarıdan vermek (dependency injection) burada çok sade bir biçimde karşımıza çıkıyor: Tek yaptığımız, gizli bir bağımlılığı açık bir parametreye dönüştürmek. Aynı yaklaşım rastgele sayı üreteçleri, dosya sistemi erişimi ve ağ istemcileri için de geçerlidir. Üretimde gerçek değeri geçirir, testte sabit olanı kullanırsın.
Zaman bitiş anının kendisi "aktif değil" sayılıyor; sınır davranışını testte açıkça belirtmek, ileride bu kararın yanlışlıkla değişmesini engeller.
Bir sıralama fonksiyonu yaz (basit bir ekleme sıralaması yeterli) ve doğruluğunu tek tek örneklerle değil, değişmezlerle sına: Sonuç artan sırada olmalı, uzunluk korunmalı ve elemanların çokluğu (multiset) değişmemeli. Rastgele üretilmiş dilimlerle bu değişmezleri doğrula. Fuzzing'in mantığını sabit tohumlu bir rastgele üreteçle taklit et.
İpucu
math/rand/v2 paketindeki rand.New(rand.NewPCG(1, 2)) sabit tohumlu bir üreteç verir; çıktı her çalıştırmada aynı olur. Çokluğu karşılaştırmak için iki dilimin frekans haritalarını kıyasla.
Çözümü göster
package main
import (
"fmt"
"maps"
"math/rand/v2"
"slices"
)
func InsertionSort(in []int) []int {
out := slices.Clone(in)
for i := 1; i < len(out); i++ {
key := out[i]
j := i - 1
for j >= 0 && out[j] > key {
out[j+1] = out[j]
j--
}
out[j+1] = key
}
return out
}
func isSorted(s []int) bool {
for i := 1; i < len(s); i++ {
if s[i-1] > s[i] {
return false
}
}
return true
}
func counts(s []int) map[int]int {
m := make(map[int]int, len(s))
for _, v := range s {
m[v]++
}
return m
}
func main() {
r := rand.New(rand.NewPCG(1, 2)) // sabit tohum: çıktı deterministik
violations := 0
for range 500 {
n := r.IntN(20)
input := make([]int, n)
for i := range input {
input[i] = r.IntN(50) - 25 // negatifler de olsun
}
sorted := InsertionSort(input)
switch {
case !isSorted(sorted):
violations++
fmt.Println("sıralı değil:", input, "→", sorted)
case len(sorted) != len(input):
violations++
fmt.Println("uzunluk değişti:", input, "→", sorted)
case !maps.Equal(counts(sorted), counts(input)):
violations++
fmt.Println("elemanlar değişti:", input, "→", sorted)
}
}
fmt.Println("denenen rastgele durum: 500")
fmt.Println("ihlal sayısı:", violations)
// Bilinen sınır durumları
fmt.Println("boş:", InsertionSort(nil))
fmt.Println("tek:", InsertionSort([]int{7}))
fmt.Println("tersten:", InsertionSort([]int{5, 4, 3, 2, 1}))
fmt.Println("tekrarlı:", InsertionSort([]int{3, 1, 3, 1, 3}))
}denenen rastgele durum: 500 ihlal sayısı: 0 boş: [] tek: [7] tersten: [1 2 3 4 5] tekrarlı: [1 1 3 3 3]
Bu yaklaşım özellik temelli test (property-based testing) olarak bilinir ve Go'nun fuzzing desteği tam olarak bunu otomatikleştirir. Üç değişmezin birlikte sağlanması, sıralamanın doğru olduğunu neredeyse kanıtlar: Sıralı olmak tek başına yetmez (fonksiyon her şeyi silip boş dilim döndürebilirdi), uzunluk tek başına yetmez, ama üçü birlikte güçlü bir güvence verir.
Sabit tohum kullanmak, testin her çalıştırmada aynı durumları denemesini sağlar. Gerçek fuzzing'de tohum rastgeledir ve bulunan bozuk girdiler kalıcı test durumlarına dönüştürülür. Sıralama algoritmalarını Temel Sıralama dersinde ayrıntısıyla inceleyeceksin.
Kısa sınav
t.Error ile t.Fatal arasındaki fark nedir?
Bir test yardımcı fonksiyonunda t.Helper() çağırmak ne sağlar?
Tablo güdümlü testlerde t.Run kullanmanın faydası nedir?
Example fonksiyonundaki // Output: yorumu ne işe yarar?
Yüzde yüz kod kapsaması ne anlama gelir?
Fuzzing hangi tür sorunları bulmakta özellikle iyidir?
Özet
- Test altyapısı dilin parçasıdır:
_test.godosyaları,Testile başlayan fonksiyonlar vego testkomutu yeterlidir. - Hata mesajı ne çağrıldığını, ne çıktığını ve ne beklendiğini söylemelidir.
t.Errordevam eder,t.Fataldurdurur; yardımcı fonksiyonlardat.Helper()çağrılır.- Tablo güdümlü testler +
t.Run, Go'nun standart test biçimidir; her duruma isim ver. b.Loop()ile benchmark yazılır;-benchmembellek ayırmalarını gösterir ve genelde süreden daha öğreticidir.Examplefonksiyonları hem belge hem testtir;// Output:yorumu doğrulanır.- Kapsama, dokunulmamış bölgeleri bulmak içindir; bir hedef sayı değildir.
- Fuzzing değişmezleri sınar ve beklenmedik girdileri bulur; bulduğu girdiler kalıcı test durumuna dönüşür.
- Zamanı, rastgeleliği ve dış kaynakları parametre olarak vermek kodu test edilebilir kılar.