---
title: Test
source: 'https://academia.sh/tr/kurslar/react-native/test'
course: 'React Native'
language: tr
updated: '2026-10-21T05:02:55+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Beklenen kayıt listesini gerçek kayıt listesiyle karşılaştırır'
    - 'Düğmeye basılınca yalnız metin düğümünün güncellendiğini gösterir'
    - 'Geçen ve kalan bir testin çıktısını okur'
    - 'Bileşen testi ile uçtan uca testin neyi gördüğünü ayırır'
---

# Test

Bir test, güncellemenin beklenen kayıt listesini gerçek kayıt listesiyle karşılaştırır. Ders düğmeye basılınca metnin güncellendiğini ve testin neyi göremediğini ölçer.

Önceki ders hatanın ağaçta bıraktığı izi ölçtü. Hata ayıklama bir şeyin yanlış gittiğini sonradan bulmaktır; test ise doğru gitmesi gereken şeyi önceden yazıp her değişiklikte denetlemektir. Bu ders bir güncellemenin beklenen sonucunu kayıt listesi olarak yazar ve gerçek listeyle karşılaştırır.

Kursun sorusu: **bu güncelleme görünüm ağacındaki düğüme ne yapıyor?** Yanıtlar korunan, güncellenen, kurulan ve sökülen; korunan dışındakilerin toplamı komuttur. Kural çekirdek dosyadadır.

```javascript
// fate.mjs — bir guncellemenin gorunum agacindaki her dugume ne yaptigini siniflandirir
export const FATES = ["korunan", "guncellenen", "kurulan", "sokulen"];

export function el(type, props = {}, children = [], key = null) {
  return { type, props, children, key };
}

function segment(node) {
  return node.key === null ? node.type : `${node.type}[${node.key}]`;
}

function identity(node, index) {
  return node.key === null ? `#${index}` : `key:${node.key}`;
}

function sameProps(a, b) {
  const names = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort();
  return names.every((n) => JSON.stringify(a[n]) === JSON.stringify(b[n]));
}

function whole(node, path, fate, ops) {
  const here = `${path}/${segment(node)}`;
  ops.push({ fate, path: here });
  node.children.forEach((child) => whole(child, here, fate, ops));
}

export function reconcile(prev, next, path = "", ops = []) {
  if (prev === null) {
    whole(next, path, "kurulan", ops);
    return ops;
  }
  if (next === null) {
    whole(prev, path, "sokulen", ops);
    return ops;
  }
  if (prev.type !== next.type || prev.key !== next.key) {
    whole(prev, path, "sokulen", ops);
    whole(next, path, "kurulan", ops);
    return ops;
  }
  const here = `${path}/${segment(next)}`;
  ops.push({ fate: sameProps(prev.props, next.props) ? "korunan" : "guncellenen", path: here });
  const before = new Map(prev.children.map((child, i) => [identity(child, i), child]));
  const matched = new Set();
  next.children.forEach((child, i) => {
    const id = identity(child, i);
    matched.add(id);
    reconcile(before.has(id) ? before.get(id) : null, child, here, ops);
  });
  prev.children.forEach((child, i) => {
    if (!matched.has(identity(child, i))) reconcile(child, null, here, ops);
  });
  return ops;
}

export function printOps(ops) {
  ops.forEach((op) => console.log(`${op.fate}: ${op.path}`));
}

export function countFates(ops) {
  for (const name of FATES) {
    console.log(`${name}: ${ops.filter((op) => op.fate === name).length}`);
  }
  console.log(`komut: ${ops.filter((op) => op.fate !== "korunan").length}`);
}
```

Test edilecek model bir sayaç ekranıdır: bir metin ve bir düğme. Düğmeye basmak sayacı bir artırır ve metin yeni sayıyı gösterir. Ekranı `renderCounter(count)` kurar. Test yardımcısı `check` bir adı, beklenen kayıtları ve eski ile yeni ağacı alır. Beklenen kayıtlar `korunan` dışındaki akıbetlerin `akıbet: yol` biçiminde yazılmış hâlidir; `check` gerçek kayıtları aynı biçime çevirir, karşılaştırır ve `GECTI` ya da `KALDI` yazar.

```javascript
// counter.mjs — sayac ekranini gorunum agacina cevirir
import { el } from "./fate.mjs";

export function renderCounter(count) {
  return el("Counter", {}, [
    el("Text", { value: count }),
    el("Button", { label: "Artir" }),
  ]);
}
```

```javascript
// check.mjs — beklenen kayit listesini gercek kayit listesiyle karsilastirir
import { reconcile } from "./fate.mjs";

export function check(name, expected, before, after) {
  const actual = reconcile(before, after)
    .filter((op) => op.fate !== "korunan")
    .map((op) => `${op.fate}: ${op.path}`);
  const passed = JSON.stringify(actual) === JSON.stringify(expected);
  console.log(`${passed ? "GECTI" : "KALDI"}: ${name}`);
  if (!passed) {
    console.log(`beklenen: ${expected.join(" | ") || "bos"}`);
    console.log(`gercek: ${actual.join(" | ") || "bos"}`);
  }
}
```

`renderCounter` durumdan bir ağaç üretir. `check` korunan kayıtları atar, çünkü bir güncellemenin sorusu ne değiştiğidir; değişmeyenleri saymak testi kırılgan yapar. Beklenen liste de bu yüzden yalnız değişenleri yazar.

## Düğmeye Basmak

İlk testte kullanıcı düğmeye basar. Sayaç sıfırdan bire geçer. Beklenen: yalnız metin düğümü güncellenir, düğme ve kök korunur.

```javascript
// main.mjs
import { renderCounter } from "./counter.mjs";
import { check } from "./check.mjs";

check("dugmeye basmak metni gunceller", ["guncellenen: /Counter/Text"], renderCounter(0), renderCounter(1));
```

```text
GECTI: dugmeye basmak metni gunceller
```

Test geçti. Gerçek güncelleme tek kayıt verdi: `/Counter/Text` güncellenen. Düğmenin etiketi değişmediği için düğme korunan kaldı ve beklenen listeye girmedi.

## Değişmeyen Güncelleme

İkinci testte hiçbir şey değişmez: aynı sayaç değeriyle ağaç yeniden kurulur. Beklenen liste boştur. Yeniden çizim komut değildir; bu test bunu bir kural olarak sabitler.

```javascript
// main.mjs
import { renderCounter } from "./counter.mjs";
import { check } from "./check.mjs";

check("ayni deger komut vermez", [], renderCounter(3), renderCounter(3));
```

```text
GECTI: ayni deger komut vermez
```

Boş liste de bir beklentidir. Test, gereksiz bir güncellemenin ağaca komut göndermediğini sabitler; ileride biri sayaca her çizimde değişen bir özellik eklerse bu test kalır.

## Kalan Test

Üçüncü testte beklenti yanlıştır: yazar düğmenin de güncellendiğini sanmıştır. Gerçek güncelleme yalnız metni değiştirir. Test kalır ve iki listeyi alt alta yazar.

```javascript
// main.mjs
import { renderCounter } from "./counter.mjs";
import { check } from "./check.mjs";

const expected = ["guncellenen: /Counter/Text", "guncellenen: /Counter/Button"];
check("yanlis beklenti", expected, renderCounter(0), renderCounter(1));
```

```text
KALDI: yanlis beklenti
beklenen: guncellenen: /Counter/Text | guncellenen: /Counter/Button
gercek: guncellenen: /Counter/Text
```

Kalan testin çıktısı hatanın yerini söyler: beklenen listede fazladan bir kayıt var. Bu, iki yönde de bir bulgudur. Ya beklenti yanlıştır, ya da uygulama düğmeyi güncellemesi gerekirken korumuştur. Test hangisi olduğuna karar vermez; yalnız farkı gösterir.

## Düğüm Değişince Beklenti

Şimdiye kadar yalnız özellik değişti. Gerçek bir ekran, sınıra ulaşıldığında düğmenin yerine bir uyarı koyabilir. Bu durumda testin beklentisi başka bir akıbet türüne geçer: düğme sökülür, uyarı kurulur. Aşağıdaki ölçümde iki ağaç doğrudan `el` ile kurulur ve beklenen liste iki kayıt taşır.

```javascript
// main.mjs
import { el } from "./fate.mjs";
import { check } from "./check.mjs";

const before = el("Counter", {}, [el("Text", { value: 9 }), el("Button", { label: "Artir" })]);
const after = el("Counter", {}, [el("Text", { value: 10 }), el("Limit", { text: "Sinira ulasildi" })]);
const expected = ["guncellenen: /Counter/Text", "sokulen: /Counter/Button", "kurulan: /Counter/Limit"];
check("sinira ulasinca dugme yerini uyariya birakir", expected, before, after);
```

```text
GECTI: sinira ulasinca dugme yerini uyariya birakir
```

Test geçti ve üç kaydın sırası beklenenle örtüştü. Burada iki şey görülür. Birincisi, beklenen liste yalnız değişenleri yazsa da bir güncellemenin birden çok akıbeti olabilir: metin güncellendi, düğme söküldü, uyarı kuruldu. İkincisi, `check` listeleri sıralı karşılaştırır. Aynı üç kayıt başka bir sırayla yazılsaydı test, uygulama doğru olduğu hâlde kalırdı. Kayıtların sırası kuralın bir sonucudur; testi yazan kişi sırayı kuraldan öğrenir, tahmin etmez.

Bu ölçüm bir karşı örnektir: önceki testler tek kayıtlıydı ve "test bir kaydı denetler" izlenimi verebilirdi. Test bir kayıt listesini denetler; liste bir kayıt kadar da uzun olabilir, üç kayıt kadar da.

## Yaygın Yanılgı

İlk yanılgı, geçen bir testin uygulamanın doğru olduğunu kanıtladığı sanısıdır. Geçen test yalnız yazılan beklentinin tuttuğunu söyler. Beklenti eksikse ya da yanlışsa uygulama yanlış kalır ve test yine geçer. Yukarıdaki üçüncü testte durum tersiydi: beklenti yanlıştı ve test uygulamayı değil beklentiyi suçladı.

İkinci yanılgı, her şeyi yazmanın testi sağlamlaştırdığı sanısıdır. `check` bu yüzden `korunan` kayıtlarını atar. Ağaçtaki her düğümün akıbetini listeye yazan bir test, ekrana yeni bir düğüm eklendiği anda kalır; oysa eklenen düğüm denetlenen davranışla ilgisiz olabilir. Sağlam test, denetlediği davranışın bıraktığı kayıtları yazar ve ötesini sessiz bırakır.

Üçüncü yanılgı, ağaç testinin yerel tarafı da doğruladığı sanısıdır. Ağaç testi, JavaScript tarafının ağaca ne bıraktığını denetler; ekranda ne göründüğünü denetlemez. Bu ayrım dersin sınırlayıcı ölçümünde somutlaşır.

## Bileşen Testi ve Uçtan Uca Test

Yukarıdaki testler ağaca bakar: bir bileşen testi bir ekranı kurar, bir olayı tetikler ve ağacın nasıl değiştiğini denetler. Hızlı çalışır ve gerçek bir telefon istemez, çünkü yerel görünüm yoktur; yalnız ağaç vardır. Aşağıdaki parça böyle bir testin kaynak biçimini gösterir; model onu çalıştırmaz.

```jsx
// Platform kodu: Counter testi
test("dugmeye basmak metni gunceller", () => {
  render(<Counter />);
  fireEvent.press(screen.getByText("Artir"));
  expect(screen.getByText("1")).toBeTruthy();
});
```

Uçtan uca test ise gerçek uygulamayı gerçek bir ekranda açar, düğmeye gerçekten dokunur ve ekrana bakar. Ağaçta görünmeyen şeyleri de görür: yerel tarafın çizdiği piksel, klavyenin açılması, izin penceresi. Yavaştır ve kırılgandır, bu yüzden azdır. Bir ekran düzyazıda anlatılır; model ağaca bakar ve ekran ağaç değildir.

## Kaynak Parçasını Satır Satır Okumak

Bileşen testinin kaynak parçası beş satırdır ve her satırın modelde bir karşılığı vardır.

- `render(<Counter />)` ekranı bir test ağacına kurar. Modelde bu, `renderCounter(0)` ile ilk ağacı üretmeye denk gelir. Gerçek yerel görünüm kurulmaz.
- `fireEvent.press(screen.getByText("Artir"))` önce ağaçta etiketi "Artir" olan düğümü bulur, sonra ona bir basma olayı gönderir. Modelde olay yoktur; basmanın sonucu `renderCounter(1)` çağrısıyla temsil edilir.
- `expect(screen.getByText("1")).toBeTruthy()` olaydan sonra ağaçta "1" metnini taşıyan bir düğümün bulunduğunu söyler. Modeldeki karşılığı, `/Counter/Text` düğümünün güncellenen çıkmasıdır.

Aralarındaki fark önemlidir. Kaynak parçası sonucu içerik üzerinden denetler: "1" metni ağaçta var mı? Model ise akıbet üzerinden denetler: metin düğümü güncellendi mi? Sorgu, düğümün yerinde güncellendiğini mi yoksa söküp yeniden mi kurulduğunu mu ayırt etmez; ikisi de ağaçta "1" bırakır. Akıbeti denetlemek isteyen test, sorguya ek olarak düğümün kimliğini de saklamalıdır. Bu dersin kural tarafı o ayrımı görünür kılar.

## Testin Adı

Testin adı kısa bir cümledir ve neyin sınandığını söyler: "düğmeye basmak metni günceller" bir davranışı adlandırır, "test 1" adlandırmaz. İyi ad, test kaldığında okuyanın kodu açmadan neyin bozulduğunu anlamasını sağlar. Bu derste kalan test bu yüzden "yanlış beklenti" adını taşır: ad, hatanın uygulamada değil beklentide olduğunu baştan söyler. Ad ayrıca testin neyi sınamadığını da dürüstçe sınırlar: "metni günceller" diyen bir test düğmenin etiketi hakkında bir şey söylemez, ve bunu başka bir test üstlenir.

## Beklenti Nasıl Yazılır

Beklenen listeyi yazmanın bir sırası vardır ve sıra, listeyi uygulamadan kopyalamaktan korur. Önce güncellemenin kullanıcıya ne vaat ettiği düzyazıyla yazılır: "düğmeye basılınca sayı bir artar." Sonra bu vaadin ağaçta hangi düğümlere dokunması gerektiği düşünülür: sayıyı gösteren düğüm değişir, düğme ve kök değişmez. Ancak bundan sonra liste yazılır ve `check` çalıştırılır.

Sırayı ters çevirip önce `check`'i koşturmak ve çıkan gerçek listeyi beklenen olarak yapıştırmak testi hemen geçirir, ama hiçbir şey sınamaz. Böyle bir test uygulamanın bugünkü davranışını dondurur; bugünkü davranış yanlışsa yanlışı da dondurur. Kalan test bu yüzden zararsız değil, değerlidir: beklenti ile gerçek arasındaki fark, bir insanın iki şeyi ayrı ayrı düşündüğünün kanıtıdır.

## Hangi Testi Nerede Yazmalı

Üç ölçüm de ağaç düzeyindeydi. Pratikte hangi sorunun hangi testle sorulacağı şöyle ayrılır.

- Bir olayın hangi düğümü değiştirdiği sorusu ağaç düzeyindedir. Bileşen testi bunu hızlı ve kararlı yanıtlar; her değişiklikte koşabilir.
- Bir düğümün kimliğini koruyup korumadığı da ağaç sorusudur ama sorgu ile görünmez. Güncellenen ile sökülen arasındaki fark, ancak akıbet ölçen bir araçla ya da düğümün kimliğini saklayan bir testle yakalanır.
- Ekranda ne göründüğü, klavyenin açılıp açılmadığı, bir izin penceresinin çıkıp çıkmadığı ağaç dışıdır. Bunlar uçtan uca testin işidir.

Uçtan uca test yavaştır; her dokunuşta gerçek bir uygulama açılır. Bu yüzden az sayıda ve en önemli yolları kapsayan testlerle sınırlı tutulur. Ağaç düzeyindeki testler çoğunluğu oluşturur. Bu dağılım, hataların çoğunun ağaçta yakalanabilmesine ve ağaçtaki hatanın ucuza bulunmasına dayanır.

## Sınırlayıcı Ölçüm

Son ölçüm testin neyi göremediğini gösterir. Modelde yazı rengi yoktur; ağaçta olmayan bir ayrıntı kural için de yoktur. Aynı sayaç değeriyle kurulan iki ekran, renkleri ne olursa olsun, aynı ağacı üretir. Aşağıdaki ölçüm bu iki ekranı karşılaştırır ve süzgeci metin düğümüne çevirir.

```javascript
// main.mjs
import { reconcile, printOps } from "./fate.mjs";
import { renderCounter } from "./counter.mjs";

const before = renderCounter(1);
const after = renderCounter(1);
const ops = reconcile(before, after);
printOps(ops.filter((op) => op.path === "/Counter/Text"));
```

```text
korunan: /Counter/Text
```

Odak düğüm `/Counter/Text`. İki ekran ağaç olarak aynıdır ve metin düğümü korunan çıktı. Bir test yazı rengi gibi ağaca girmeyen bir farkı bilemez: kural özelliğe bakar, pikselde ne olduğuna bakmaz. Rengin doğru olduğunu denetlemek isteyen bir test, rengi ağaca özellik olarak taşımalı ya da uçtan uca testle ekrana bakmalıdır.

Sayaç bire geçtiğinde aynı süzgeçle `/Counter/Text` güncellenen çıkar (ilk ölçüm). Dersin akıbeti budur: bir güncellemeyi sınayan test, doğrulanan şeyi güncellenen düğümün yolunda arar.

**BU5.** Model, bu akıbetin kuralını kurar; model çerçevenin kendisi değildir. Modelde test bir kayıt listesi karşılaştırmasıdır ve `korunan` kayıtları atar. Gerçek bir bileşen testi bir metni, bir erişilebilirlik etiketini ya da bir rolü sorgular; sorgu ağacın bir düğümünü bulur, ama bulduğu düğümün güncellendiğini ya da yeniden kurulduğunu söylemez. Modelde ölçülen beklentiler gerçek bir testin sorgularına bire bir karşılık gelmez.

## Özet

- Bu dersin akıbeti: güncellenen. Düğmeye basılınca `/Counter/Text` düğümü güncellendi; düğme ve kök korunan kaldı.
- Beklenen kayıt listesi `korunan` dışındaki akıbetleri yazar; `check` bunu gerçek listeyle karşılaştırıp `GECTI` ya da `KALDI` verir.
- Değişmeyen bir güncellemenin beklentisi boş listedir; yeniden çizim komut değildir.
- Beklenti önce düzyazıyla, sonra kayıt listesi olarak yazılır; gerçek listeyi beklenen diye yapıştırmak hiçbir şey sınamaz.
- Bileşen testi ağaca bakar; ağaca girmeyen bir ayrıntıyı, örneğin yazı rengini, ancak uçtan uca test görür.

## Sonraki Adım

Testler ağaca bakar ama ağacın altındaki yerel katmana inmez. Sıradaki ders, `Yerel Modül Yazımı`, ağacın bir düğümünün arkasında platforma özgü kod yazıldığında güncellemenin ağaçta ne yaptığını ölçer ve kursun son dersi `Derleme ve Yayın`a köprü kurar.
