---
title: 'Test Paketi Temelleri'
source: 'https://academia.sh/tr/kurslar/go-uretim/test-paketi-temelleri'
course: 'Üretim Go: Test, Araçlar ve Başarım'
language: tr
updated: '2026-09-13T05:08:47+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir test dosyasındaki test işlevi sayısını kaynaktan, testin geçip geçmediğini yalnız koşturarak okur'
    - 'Aynı test dosyasının doğru ve bozuk bir kaynağa karşı verdiği kararın nasıl değiştiğini koşturarak karşılaştırır'
    - 'Hiçbir iddia içermeyen bir test işlevinin de geçtiğini göstererek "geçti" ile "doğru" arasındaki farkı sınırlar'
---

# Test Paketi Temelleri

Aynı test dosyası, kaynağın kaç test işlevi içerdiğini metinden sayarak, testin verdiği kararı ise yalnız koşturarak söylüyor: doğru bir kaynakta iki test de geçiyor, bozuk bir kaynakta test sayısı değişmeden karar tersine dönüyor. Sınırlayıcı ölçüm, hiçbir iddia taşımayan bir test işlevinin de aynı biçimde geçtiğini koşturarak gösteriyor.

Önceki kurs bir değerin sınırı geçerken tip bilgisinin çoğunlukla kaybolduğunu ölçtü:
kaynağa bakan biri, bir sınırın öte yanındaki değerin hangi tipte olduğunu çoğu zaman
göremiyordu. Bu kurs aynı soruyu bir düzey yukarı taşıyor — artık tek bir değerin değil,
bütün bir programın hakkında bilinenler konu. Bir programın doğru çalıştığını, hangi
satırlarının koştuğunu, nerede bellek ayırdığını ve hangi platforma derlendiğini kaynağa
bakarak göremezsiniz. Öyleyse bu bilgiyi kim söylüyor — kaynağın kendisi mi, koşum
olmadan bir aracın türettiği bir yanıt mı, yoksa yalnız çalıştırarak öğrenilen bir sonuç mu?

Bu ilk ders soruyu en dar biçimiyle soruyor: bir test işlevi geçti mi, kaldı mı? Ölçüm
boyunca konu içinde sürecek küçük bir paket kullanılıyor — bir depo kalemini ve kalem
listesinin toplam değerini tutan `envanter` paketi. Kalemin kendisi basit: bir ad, bir
adet, kuruş cinsinden bir birim fiyat. Toplam değer de basit bir çarpım-toplam. Bu dersin
sorusu paketin ne yaptığı değil, paketin **doğru** yaptığını kimin söylediği.

Bu soru üretim ortamında çalışan bir programda özel bir ağırlık taşıyor. Bir kaynak
gözden geçirmesi, bir dosyanın satırlarını okuyup mantığın doğru göründüğüne karar
verebilir — ama "doğru göründü" ile "doğru çalıştığı sınandı" arasında bir uçurum var
ve bu uçurumu kapatan tek şey kaynağın yanına yazılmış, gerçekten koşturulmuş bir test.
Konunun geri kalan beş dersi bu uçurumun farklı köşelerini ölçüyor: vaka listesinin
kendisi kaynakta mı yazılı, ağ katmanı gerçekten devreye girmeden nasıl sınanıyor, bir
bağımlılığın yerine geçen sahte nesne neyi eksik bırakıyor, iki yazımın hangi sayısı
tekrarlanabilir ve kapsama oranının söylediği şeyin sınırı nerede. Hepsi aynı kökten
başlıyor: bir testin verdiği kararın kaynaktan değil, koşumdan geldiği.

## Test İşlevi ve Yardımcı Dilin Kendi Kuralına Uyar

Test paketi, dilin standart kitaplığının bir parçası ve kendi kuralını dayatıyor: bir işlev test
paketi tarafından test olarak tanınmak istiyorsa adı `Test` ile başlamalı ve `Test`ten sonrası
küçük harfle başlamamalı (`TestToplam` tanınır, `Testtoplam` tanınmaz), tek bir `*testing.T`
parametresi almalı ve dosyanın adı `_test` ile bitmeli. Bu üç kural derleyicinin denetlediği bir
sözdizimi değil — test paketinin kendi tarama kuralı ve kaynağı okuyan biri bu kuralı bildiğinde,
hangi işlevlerin test olarak çalışacağını **metinden** çıkarabiliyor. Bu kuralın kendisi bir kayıt
adımı gerektirmiyor: bir test işlevini ayrı bir listeye eklemek ya da bir çağrıyla bildirmek
gerekmiyor, yalnız adı ve imzası doğru olduğunda test paketi onu kendiliğinden buluyor.

Aynı dosyada bir de `orneklerVer` işlevi var, ama bu bir test değil — adı `Test` ile
başlamıyor, bu yüzden test paketi onu hiç çalıştırmıyor. Bunun yerine iki test işlevi
tarafından çağrılan bir yardımcı: aynı örnek kalem listesini tekrar tekrar yazmamak için
bir kez tanımlanmış ve gövdesindeki `t.Helper()` çağrısı test paketine "bir hata
buradan değil, beni çağıran satırdan bildirilsin" diyor. Bu ayrım — hangi işlevin test,
hangisinin yardımcı olduğu — da kaynaktan okunabiliyor; test paketi bu kararı vermek
için hiçbir işlevi çalıştırmak zorunda kalmıyor, yalnız adına ve imzasına bakıyor.

**TS1.** Aşağıdaki test dosyası iki işlev tanımlıyor, `TestToplamDeger` ve
`TestBosIddia`; ikisi de adları ve imzalarıyla test paketinin kuralına uyuyor ve
kaç tane olduğu kaynaktaki `func Test` geçişleri sayılarak — hiçbir araç çağrılmadan —
öğrenilebiliyor.

```go
// araclar/araclar.go — go komut ailesini gecici bir modulde program icinden cagiran ortak yordamlar
package araclar

import (
	"os"
	"os/exec"
	"path/filepath"
)

// Kur verilen dosyalarla gecici bir modul olusturur ve dizinini dondurur; yol hicbir yerde basilmaz.
func Kur(dosyalar map[string]string) string {
	dizin, _ := os.MkdirTemp("", "sinama")
	os.WriteFile(filepath.Join(dizin, "go.mod"), []byte("module sinama\n\ngo 1.24\n"), 0o644)
	for ad, icerik := range dosyalar {
		os.WriteFile(filepath.Join(dizin, ad), []byte(icerik), 0o644)
	}
	return dizin
}

// Cagir dilin kendi komutunu gecici modulde kosturur; ciktinin kendisi degil basari donuyor.
func Cagir(dizin string, ekOrtam []string, arg ...string) (string, bool) {
	cmd := exec.Command("go", arg...)
	cmd.Dir = dizin
	cmd.Env = append(append(os.Environ(), "GOTOOLCHAIN=local"), ekOrtam...)
	cikti, err := cmd.CombinedOutput()
	return string(cikti), err == nil
}
```

`Kur`, ölçümün her seferinde tamamen boş bir modülden başlaması için gerekli; aksi
takdirde bir önceki koşumun bıraktığı bir dosya sonucu etkileyebilir. `Cagir` ise dilin
komut ailesini her zaman aynı yoldan çağırıyor: alt süreç olarak, sabit bir ortamla
ve yalnız çıktıyla başarı bilgisini geri döndürerek. Bu iki yordam konunun altı dersi
boyunca aynı biçimde kullanılıyor; hiçbir ders komut adını düzyazıda anmıyor, yalnız
kod bloğunun içinde bir çağrının argümanı olarak geçiyor.

`araclar` işlevleri kendi paketinde duruyor — Go Temelleri kursunda kurulan paket ve
görünürlük ayrımı burada aynen işliyor: `Kur` ve `Cagir` büyük harfle başladığı için
`main` paketinden `ders/araclar` yolunu içe aktararak çağrılabiliyor. Ölçümün asıl gövdesi
— hangi kaynağın sınandığı, hangi sorunun sorulduğu — her zaman `main` paketinde kalıyor;
paket sınırı yalnız tekrarlanan kurulum ve çağrı mantığını bir kez yazıp altı derste de
kullanmak için çiziliyor.

## Karar Yalnız Koşarak Geliyor

Test dosyasının kaç test içerdiği kaynaktan okunabiliyor, ama bu testlerin **geçip
geçmediği** aynı biçimde okunamıyor. `go test` çağrıldığında test paketi önce paketteki
bütün dosyaları derliyor, sonra adı `Test` ile başlayan işlevleri bulup her birini
sırayla çalıştırıyor ve her birinin sonunda kesilip kesilmediğine bakıyor. Bu iki adım —
derleme ve çalıştırma — birbirinden ayrı: bir test dosyası derlenebilir olduğu hâlde
içindeki testlerin hiçbiri geçmeyebilir, ya da tam tersi. Derleme adımı da bir bilgi
kaynağı, ama farklı bir sınıftan: paket derlenmiyorsa bu, testleri hiç çalıştırmadan,
yalnız kaynağı derleyiciden geçirerek öğrenilebiliyor — o hâlde bu bir araç bilgisi.
Derlenen bir paketin testlerinin geçip geçmediği ise derleme bittikten sonra, testler
fiilen çalıştırıldıktan sonra ortaya çıkıyor; bu da bir koşum bilgisi. Aşağıdaki ölçüm
ikisini de karıştırmadan ayırıyor: `envanter`
paketinin doğru bir sürümüne karşı iki testi de koşturuyor, sonra aynı test dosyasını
hiç değiştirmeden paketin bozuk bir sürümüne karşı yeniden koşturuyor.

```go
// olcum.go — testin karari kaynaktan degil kosturarak okunuyor
package main

import (
	"fmt"
	"strings"

	"ders/araclar"
)

const envanterMetni = `package sinama

type Kalem struct {
	Ad    string
	Adet  int
	Fiyat int
}

func ToplamDeger(kalemler []Kalem) int {
	toplam := 0
	for _, k := range kalemler {
		toplam += k.Adet * k.Fiyat
	}
	return toplam
}
`

const bozukEnvanterMetni = `package sinama

type Kalem struct {
	Ad    string
	Adet  int
	Fiyat int
}

func ToplamDeger(kalemler []Kalem) int {
	toplam := 0
	for _, k := range kalemler {
		toplam += k.Adet
	}
	return toplam
}
`

const testMetni = `package sinama

import "testing"

func orneklerVer(t *testing.T) []Kalem {
	t.Helper()
	return []Kalem{{"kalem", 3, 250}, {"defter", 2, 990}}
}

func TestToplamDeger(t *testing.T) {
	kalemler := orneklerVer(t)
	if got := ToplamDeger(kalemler); got != 2730 {
		t.Errorf("ToplamDeger = %d, beklenen 2730", got)
	}
}

func TestBosIddia(t *testing.T) {
	orneklerVer(t)
}
`

func testSayisi(kod string) int {
	return strings.Count(kod, "\nfunc Test")
}

func main() {
	fmt.Println("-- kaynak: test dosyasindaki test sayisi --")
	fmt.Println("dosyadaki test islevi sayisi:", testSayisi(testMetni))

	fmt.Println()
	fmt.Println("-- kosum: dogru kaynaga karsi karar --")
	dogru := araclar.Kur(map[string]string{"envanter.go": envanterMetni, "envanter_test.go": testMetni})
	ciktiDogru, _ := araclar.Cagir(dogru, nil, "test", "-v", "./...")
	fmt.Println("TestToplamDeger gecti mi:", strings.Contains(ciktiDogru, "--- PASS: TestToplamDeger"))
	fmt.Println("TestBosIddia gecti mi:", strings.Contains(ciktiDogru, "--- PASS: TestBosIddia"))

	fmt.Println()
	fmt.Println("-- kosum: ayni test dosyasi, bozuk kaynaga karsi karar --")
	fmt.Println("dosyadaki test islevi sayisi:", testSayisi(testMetni))
	bozuk := araclar.Kur(map[string]string{"envanter.go": bozukEnvanterMetni, "envanter_test.go": testMetni})
	ciktiBozuk, _ := araclar.Cagir(bozuk, nil, "test", "-v", "./...")
	fmt.Println("TestToplamDeger gecti mi:", strings.Contains(ciktiBozuk, "--- PASS: TestToplamDeger"))
}
```

```
-- kaynak: test dosyasindaki test sayisi --
dosyadaki test islevi sayisi: 2

-- kosum: dogru kaynaga karsi karar --
TestToplamDeger gecti mi: true
TestBosIddia gecti mi: true

-- kosum: ayni test dosyasi, bozuk kaynaga karsi karar --
dosyadaki test islevi sayisi: 2
TestToplamDeger gecti mi: false
```

**TS2.** İki koşum arasında değişen tek şey `envanter.go`'nun içeriği; test dosyası bayt
bayt aynı ve kaynaktan sayılan test sayısı da ikisinde de aynı: 2. Değişen şey, bu iki
testin **koşturulduğunda** verdiği karar — `TestToplamDeger`, birim fiyatı çarpmayı
unutan bozuk sürüme karşı çalıştığında `kaldı` diyor. Kaynağı okuyarak bu farkı
öngörmenin tek yolu, iki `ToplamDeger` gerçekleştirimini elle karşılaştırıp hangisinin
doğru olduğuna kendiniz karar vermek — test paketinin kendisi bu kararı kaynağı okuyarak
değil, `go test` çağrısını gerçekten çalıştırarak veriyor. Yukarıdaki ölçüm de tam olarak
bunu yapıyor: `Cagir` yordamı `go test -v ./...` komutunu alt süreç olarak koşturuyor ve
program yalnız çıktıdaki `--- PASS: <ad>` satırının varlığına bakarak bir doğruluk
değeri okuyor. Ne hata metni ne de testin ürettiği ham çıktı hiçbir yerde basılıyor —
yalnız sorulan tek şey döndürülüyor: bu test geçti mi.

Ölçümün iki koşumu da aynı `Kur` yordamıyla, aynı test dosyasıyla ve aynı komutla
çalışıyor; tek fark hangi `envanter.go` içeriğinin gecici modüle yazıldığı. Bu, sonucun
test çerçevesinden değil, sınanan kaynaktan geldiğini gösteriyor — ölçümün kendisi bir
kez yazılıp iki kez çağrılıyor ve iki çağrı arasındaki fark yalnız girdide.

Ölçüm `-v` bayrağını kullanıyor ve bu seçim gelişigüzel değil: bayrak verilmeden
`go test` yalnız paketin tamamı için tek bir karar veriyor — paketteki testlerin
tamamı geçtiyse başarı, herhangi biri kaldıysa başarısızlık. `TestToplamDeger` ve
`TestBosIddia`'nın **ayrı ayrı** hangi kararı verdiğini okumak için ayrıntılı çıktı
gerekiyor, çünkü test paketi bu bilgiyi yalnız `-v` istendiğinde her test için ayrı bir
satırda yazıyor. Paket düzeyindeki tek karar da bir koşum bilgisi, ama daha kaba bir
taneciklikte: hangi testin kaldığını değil, yalnız hiç kalan olup olmadığını söylüyor.
Üretim bir kod tabanında yüzlerce test tek bir pakette birikince, bu iki taneciklik
arasındaki fark — bir şeyin bozulduğunu bilmekle **neyin** bozulduğunu bilmek arasındaki
fark — pratikte büyük bir zaman farkına dönüşüyor.

## Sınırlayıcı Ölçüm: Geçen Test Ne Söylüyor

Yukarıdaki koşumda `TestBosIddia` de geçti — hem doğru kaynağa karşı hem de (dosyaya
bakılırsa) bozuk kaynağa karşı geçmeye devam ederdi, çünkü bu işlev hiçbir şeyi
sınamıyor. `orneklerVer` yardımcısını çağırıyor, dönen değeri hiç kullanmadan bırakıyor
ve hiçbir `t.Error` ya da `t.Fatal` çağrısı içermiyor. Test paketinin gözünde bir test
işlevi, çalışması bittiğinde `t.Error`, `t.Fatal` ya da bir panikle kesilmemişse
**geçmiş** sayılıyor — işlevin gövdesinde bir iddia bulunup bulunmadığı bu kararı hiç
etkilemiyor.

**TS3.** Bu, konunun ilk sınırlayıcı ölçümü: geçen bir test **doğru olduğunu**
söylemiyor, yalnız **sınadığı şeyin tuttuğunu** söylüyor — ve hiçbir şey sınamayan bir
test de aynı biçimde geçiyor, çünkü test paketinin ölçtüğü şey iddianın var olup
olmadığı değil, var olan iddianın kesilip kesilmediği. `TestBosIddia` bu farkın en yalın
görünümü: adı bir sınamayı vaat ediyor, ama gövdesi hiçbir şeyi doğrulamıyor ve test
paketinin kendisi bu boşluğu fark edecek bir mekanizma taşımıyor. Bir test paketinin bu
soruyu sormaması bir eksiklik değil, sınırının kendisi — test paketi yalnız "çalışırken
bir şey kesildi mi" sorusuna yanıt veriyor, "bu iddia yeterli mi" sorusuna değil. Bu
sınır konunun ilerleyen derslerinde de geçerli kalıyor: bir sonraki ders vaka listesini
kaynaktan sayarken, koşan alt test sayısının kaynaktaki vaka sayısıyla eşleşip
eşleşmediğini soruyor — ama hiçbir zaman "bu vakalar yeterli mi" sorusunu sormuyor,
çünkü test paketi bu soruyu hiç yanıtlamıyor.

Bu sınırın üretim kodunda somut bir karşılığı var: bir işlevin gövdesi tamamen boş
bırakılıp yalnız bir yorum satırıyla ileride tamamlanacağı not edilse bile, o işlevi
çağıran ve hiçbir şeyi doğrulamayan bir test hâlâ geçiyor. Bir sınama takımının yeşil
görünmesi — bütün testlerin geçmiş görünmesi — bu yüzden tek başına yeterli bir kanıt
değil; kaç iddianın gerçekten çalıştığı da ayrı bir sorudur ve konunun kapanış dersi
tam olarak bu ayrımı, kapsama oranı üzerinden yeniden ölçüyor.

Bu sınır test paketinin bir kusuru değil, sınırlarının nerede çizildiğinin bir sonucu.
Test paketi tek bir soruyu yanıtlamak için tasarlandı: bir çalışma kesintiye uğradı mı,
uğramadı mı. Bir iddianın **anlamlı** olup olmadığı — yanlış bir girdide de aynı sonucu
verip vermeyeceği, yeterince geniş bir aralığı kapsayıp kapsamadığı — bambaşka bir soru
ve bu soruyu yanıtlamak yazan kişinin işi, aracın işi değil. `TestBosIddia` bu farkı
en yalın biçimiyle gösteriyor çünkü hiçbir iddia içermiyor; ama aynı boşluk, yanlışlıkla
her zaman doğru çıkan bir koşulla yazılmış bir iddiada da ortaya çıkabiliyor ve o durumda
fark kaynaktan bakan bir göze çok daha az belirgin.

`envanter` paketinin kendisi de bu dersin geri kalanında sabit kalıyor: `Kalem` ve
`ToplamDeger`, konu boyunca gelişen aynı örnek üzerinde çalışıyor. Sonraki ders aynı
paketin bir fonksiyonunu tablo güdümlü bir testle sınıyor ve vaka listesinin kendisinin
nerede yazılı olduğunu soruyor.

## Özet

- Bir işlevin test paketi tarafından test sayılması, adının `Test` ile başlaması, tek
  bir `*testing.T` parametresi alması ve dosya adının `_test` ile bitmesi kuralına
  bağlı; bu kural kaynaktan okunabiliyor.
- Kaynaktaki test sayısı metinden sayılabiliyor, ama bir testin geçip geçmediği yalnız
  `go test` çalıştırılarak öğrenilebiliyor — aynı test dosyası, paketin doğru ve bozuk
  sürümlerine karşı farklı kararlar veriyor.
- Ölçüm aracı program içinden çağrılıyor ve yalnız istenen doğruluk değeri okunuyor;
  testin ham çıktısı hiçbir yerde basılmıyor.
- Sınırlayıcı ölçüm: geçen bir test doğru olduğunu değil, sınadığı şeyin tuttuğunu
  söylüyor — hiçbir iddia içermeyen bir test de aynı biçimde geçiyor.
- `envanter` paketi konu boyunca aynı örnek olarak sürüyor; bu derste yalnız
  `ToplamDeger` kullanıldı.

## Sonraki Adım

Bu derste bir testin kararının yalnız koşturarak öğrenilebildiği ve geçen bir testin "doğru" değil
yalnız "kesilmedi" dediği ölçüldü. Ölçümün kendisi de konunun geri kalanı boyunca değişmeyecek iki
yordama — `araclar.Kur` ve `araclar.Cagir` — dayandı; sonraki dersler aynı iki yordamı kendi test
dosyasıyla, kendi kaynağıyla ve kendi sorusuyla yeniden çağıracak — tek istisna, işleyiciyi
doğrudan çağırdığı için `go test`i hiç alt süreç olarak koşturmayan HTTP dersi. Sıradaki ders aynı
paketin başka bir işlevini tablo güdümlü bir testle sınıyor — bu kez soru testin kararı değil,
vaka listesinin kendisi: kaç vaka yazılı, kaç tanesi gerçekten farklı bir satırı koşturuyor ve
vaka eklemenin her zaman daha fazla şey sınamak anlamına gelip gelmediği.
