React Testing Library ile React bileşen testinde ustalaşın. Kullanıcı davranışı ve erişilebilirliğe odaklanan, bakımı kolay ve etkili testler yazmak için en iyi uygulamaları öğrenin.
React Testing Library: Küresel Ekipler için Bileşen Testi En İyi Uygulamaları
Sürekli gelişen web geliştirme dünyasında, React uygulamalarınızın güvenilirliğini ve kalitesini sağlamak büyük önem taşır. Bu durum, özellikle çeşitli kullanıcı tabanlarına ve erişilebilirlik gereksinimlerine sahip projeler üzerinde çalışan küresel ekipler için geçerlidir. React Testing Library (RTL), bileşen testine güçlü ve kullanıcı merkezli bir yaklaşım sunar. Uygulama detaylarına odaklanan geleneksel test yöntemlerinin aksine, RTL sizi bileşenlerinizi bir kullanıcının onlarla etkileşime gireceği şekilde test etmeye teşvik eder, bu da daha sağlam ve bakımı kolay testler ortaya çıkarır. Bu kapsamlı kılavuz, küresel bir kitleye uygun uygulamalar oluşturmaya odaklanarak React projelerinizde RTL kullanmanın en iyi uygulamalarını derinlemesine inceleyecektir.
Neden React Testing Library?
En iyi uygulamalara dalmadan önce, RTL'nin diğer test kütüphanelerinden neden ayrıldığını anlamak çok önemlidir. İşte bazı temel avantajları:
- Kullanıcı Merkezli Yaklaşım: RTL, bileşenleri kullanıcının bakış açısından test etmeye öncelik verir. Bileşenle bir kullanıcının yapacağı aynı yöntemlerle (örneğin, düğmelere tıklamak, giriş alanlarına yazmak) etkileşim kurarsınız, bu da daha gerçekçi ve güvenilir bir test deneyimi sağlar.
- Erişilebilirlik Odaklı: RTL, engelli kullanıcıları göz önünde bulunduracak şekilde test etmenizi teşvik ederek erişilebilir bileşenler yazmayı destekler. Bu, WCAG gibi küresel erişilebilirlik standartlarıyla uyumludur.
- Azaltılmış Bakım Maliyeti: Uygulama detaylarını (örneğin, iç state, belirli fonksiyon çağrıları) test etmekten kaçınarak, RTL testlerinin kodunuzu yeniden düzenlediğinizde (refactor) bozulma olasılığı daha düşüktür. Bu, daha sürdürülebilir ve esnek testlere yol açar.
- İyileştirilmiş Kod Tasarımı: RTL'nin kullanıcı merkezli yaklaşımı, kullanıcıların bileşenlerinizle nasıl etkileşime gireceğini düşünmek zorunda kaldığınız için genellikle daha iyi bileşen tasarımına yol açar.
- Topluluk ve Ekosistem: RTL, bol miktarda kaynak, destek ve eklenti sağlayan geniş ve aktif bir topluluğa sahiptir.
Test Ortamınızı Kurma
RTL'ye başlamak için test ortamınızı kurmanız gerekir. İşte Jest ve RTL'nin önceden yapılandırılmış olarak geldiği Create React App (CRA) kullanan temel bir kurulum:
npx create-react-app my-react-app
cd my-react-app
npm install --save-dev @testing-library/react @testing-library/jest-dom
Açıklama:
npx create-react-app my-react-app: Create React App kullanarak yeni bir React projesi oluşturur.cd my-react-app: Yeni oluşturulan proje dizinine gider.npm install --save-dev @testing-library/react @testing-library/jest-dom: Gerekli RTL paketlerini geliştirme bağımlılıkları olarak yükler.@testing-library/reacttemel RTL işlevselliğini sağlarken,@testing-library/jest-domDOM ile çalışmak için yardımcı Jest eşleştiricileri (matcher) sağlar.
Eğer CRA kullanmıyorsanız, Jest ve RTL'yi ayrı ayrı yüklemeniz ve Jest'i RTL kullanacak şekilde yapılandırmanız gerekir.
React Testing Library ile Bileşen Testi için En İyi Uygulamalar
1. Kullanıcı Etkileşimlerine Benzeyen Testler Yazın
RTL'nin temel prensibi, bileşenleri bir kullanıcının yapacağı gibi test etmektir. Bu, iç uygulama detayları yerine kullanıcının ne gördüğüne ve ne yaptığına odaklanmak anlamına gelir. Öğeleri metinlerine, rollerine veya erişilebilirlik etiketlerine göre sorgulamak için RTL tarafından sağlanan screen nesnesini kullanın.
Örnek: Bir Düğme Tıklamasını Test Etme
Basit bir düğme bileşeniniz olduğunu varsayalım:
// Button.js
import React from 'react';
function Button({ onClick, children }) {
return ;
}
export default Button;
İşte RTL kullanarak bunu nasıl test edeceğiniz:
// Button.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
describe('Button Component', () => {
it('calls the onClick handler when clicked', () => {
const handleClick = jest.fn();
render();
const buttonElement = screen.getByText('Click Me');
fireEvent.click(buttonElement);
expect(handleClick).toHaveBeenCalledTimes(1);
});
});
Açıklama:
render(): Button bileşenini sahte bironClickişleyicisiyle oluşturur.screen.getByText('Click Me'): Belgede "Click Me" metnini içeren bir öğe için sorgu yapar. Bu, bir kullanıcının düğmeyi nasıl tanımlayacağıdır.fireEvent.click(buttonElement): Düğme öğesi üzerinde bir tıklama olayını simüle eder.expect(handleClick).toHaveBeenCalledTimes(1):onClickişleyicisinin bir kez çağrıldığını iddia eder.
Bu neden uygulama detaylarını test etmekten daha iyidir: Button bileşenini farklı bir olay işleyicisi kullanacak şekilde yeniden düzenlediğinizi veya iç state'i değiştirdiğinizi hayal edin. Eğer belirli olay işleyici fonksiyonunu test ediyor olsaydınız, testiniz bozulurdu. Kullanıcı etkileşimine (düğmeye tıklama) odaklanarak, test yeniden düzenlemeden sonra bile geçerli kalır.
2. Sorguları Kullanıcı Niyetine Göre Önceliklendirin
RTL, öğeleri bulmak için farklı sorgu yöntemleri sunar. Aşağıdaki sorguları bu sırayla önceliklendirin, çünkü bunlar kullanıcıların bileşenlerinizi nasıl algıladığını ve onlarla nasıl etkileşimde bulunduğunu en iyi şekilde yansıtır:
- getByRole: Bu sorgu en erişilebilir olanıdır ve ilk tercihiniz olmalıdır. Öğeleri ARIA rollerine göre bulmanızı sağlar (örneğin, button, link, heading).
- getByLabelText: Bunu, giriş alanları gibi belirli bir etiketle ilişkili öğeleri bulmak için kullanın.
- getByPlaceholderText: Bunu, yer tutucu metinlerine göre giriş alanlarını bulmak için kullanın.
- getByText: Bunu, metin içeriklerine göre öğeleri bulmak için kullanın. Belirgin olun ve birden çok yerde görünebilecek genel metinler kullanmaktan kaçının.
- getByDisplayValue: Bunu, mevcut değerlerine göre giriş alanlarını bulmak için kullanın.
Örnek: Bir Form Girişini Test Etme
// Input.js
import React from 'react';
function Input({ label, placeholder, value, onChange }) {
return (
);
}
export default Input;
İşte önerilen sorgu sırasını kullanarak bunu nasıl test edeceğiniz:
// Input.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Input from './Input';
describe('Input Component', () => {
it('updates the value when the user types', () => {
const handleChange = jest.fn();
render();
const inputElement = screen.getByLabelText('Name');
fireEvent.change(inputElement, { target: { value: 'John Doe' } });
expect(handleChange).toHaveBeenCalledTimes(1);
expect(handleChange).toHaveBeenCalledWith(expect.objectContaining({ target: { value: 'John Doe' } }));
});
});
Açıklama:
screen.getByLabelText('Name'): "Name" etiketiyle ilişkili giriş alanını bulmak içingetByLabelTextkullanır. Bu, girişi bulmanın en erişilebilir ve kullanıcı dostu yoludur.
3. Uygulama Detaylarını Test Etmekten Kaçının
Daha önce de belirtildiği gibi, iç state'i, fonksiyon çağrılarını veya belirli CSS sınıflarını test etmekten kaçının. Bunlar, değişikliğe tabi olan ve kırılgan testlere yol açabilen uygulama detaylarıdır. Bileşenin gözlemlenebilir davranışına odaklanın.
Örnek: State'i Doğrudan Test Etmekten Kaçının
Belirli bir state değişkeninin güncellenip güncellenmediğini test etmek yerine, bileşenin bu state'e göre doğru çıktıyı oluşturup oluşturmadığını test edin. Örneğin, bir bileşen bir boolean state değişkenine göre bir mesaj gösteriyorsa, state değişkeninin kendisini test etmek yerine mesajın gösterilip gizlendiğini test edin.
4. Özel Durumlar için `data-testid` Kullanın
Genellikle `data-testid` niteliklerini kullanmaktan kaçınmak en iyisi olsa da, bunların yardımcı olabileceği özel durumlar vardır:
- Anlamsal Anlamı Olmayan Öğeler: Anlamlı bir rolü, etiketi veya metni olmayan bir öğeyi hedeflemeniz gerekiyorsa, `data-testid` kullanabilirsiniz.
- Karmaşık Bileşen Yapıları: Karmaşık bileşen yapılarında, `data-testid` kırılgan seçicilere güvenmeden belirli öğeleri hedeflemenize yardımcı olabilir.
- Erişilebilirlik Testi: `data-testid`, Cypress veya Playwright gibi araçlarla erişilebilirlik testi sırasında belirli öğeleri tanımlamak için kullanılabilir.
Örnek: `data-testid` Kullanımı
// MyComponent.js
import React from 'react';
function MyComponent() {
return (
This is my component.
);
}
export default MyComponent;
// MyComponent.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('renders the component container', () => {
render( );
const containerElement = screen.getByTestId('my-component-container');
expect(containerElement).toBeInTheDocument();
});
});
Önemli: `data-testid`'i idareli ve yalnızca diğer sorgu yöntemleri uygun olmadığında kullanın.
5. Anlamlı Test Açıklamaları Yazın
Açık ve öz test açıklamaları, her testin amacını anlamak ve hataları ayıklamak için çok önemlidir. Testin neyi doğruladığını açıkça açıklayan açıklayıcı isimler kullanın.
Örnek: İyi ve Kötü Test Açıklamaları
Kötü: `it('çalışır')`
İyi: `it('doğru selamlama mesajını gösterir')`
Daha da İyisi: `it('name propu sağlanmadığında "Merhaba, Dünya!" selamlama mesajını gösterir')`
Daha iyi olan örnek, bileşenin belirli koşullar altındaki beklenen davranışını açıkça belirtir.
6. Testlerinizi Küçük ve Odaklı Tutun
Her test, bileşenin davranışının tek bir yönünü doğrulamaya odaklanmalıdır. Birden çok senaryoyu kapsayan büyük, karmaşık testler yazmaktan kaçının. Küçük, odaklanmış testlerin anlaşılması, bakımı ve ayıklanması daha kolaydır.
7. Test Çiftlerini (Mock'lar ve Spy'lar) Uygun Şekilde Kullanın
Test çiftleri, test ettiğiniz bileşeni bağımlılıklarından izole etmek için kullanışlıdır. Harici servisleri, API çağrılarını veya diğer bileşenleri simüle etmek için mock'lar ve spy'lar kullanın.
Örnek: Bir API Çağrısını Mock'lama
// UserList.js
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
async function fetchUsers() {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
}
fetchUsers();
}, []);
return (
{users.map(user => (
- {user.name}
))}
);
}
export default UserList;
// UserList.test.js
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import UserList from './UserList';
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve([
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' },
]),
})
);
describe('UserList Component', () => {
it('fetches and displays a list of users', async () => {
render( );
// Wait for the data to load
await waitFor(() => screen.getByText('John Doe'));
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});
});
Açıklama:
global.fetch = jest.fn(...): Önceden tanımlanmış bir kullanıcı listesi döndürmek içinfetchfonksiyonunu mock'lar. Bu, gerçek bir API uç noktasına bağlı kalmadan bileşeni test etmenizi sağlar.await waitFor(() => screen.getByText('John Doe')): "John Doe" metninin belgede görünmesini bekler. Veriler asenkron olarak çekildiği için bu gereklidir.
8. Uç Durumları ve Hata Yönetimini Test Edin
Sadece mutlu senaryoyu test etmeyin. Uç durumları, hata senaryolarını ve sınır koşullarını test ettiğinizden emin olun. Bu, olası sorunları erken tespit etmenize ve bileşeninizin beklenmedik durumları zarif bir şekilde ele almasını sağlamanıza yardımcı olacaktır.
Örnek: Hata Yönetimini Test Etme
Bir API'den veri çeken ve API çağrısı başarısız olursa bir hata mesajı gösteren bir bileşen hayal edin. API çağrısı başarısız olduğunda hata mesajının doğru şekilde görüntülendiğini doğrulamak için bir test yazmalısınız.
9. Erişilebilirliğe Odaklanın
Erişilebilirlik, kapsayıcı web uygulamaları oluşturmak için çok önemlidir. Bileşenlerinizin erişilebilirliğini test etmek ve WCAG gibi erişilebilirlik standartlarını karşıladıklarından emin olmak için RTL'yi kullanın. Bazı temel erişilebilirlik hususları şunlardır:
- Anlamsal HTML: İçeriğinize yapı ve anlam kazandırmak için anlamsal HTML öğeleri (örneğin,
,,) kullanın. - ARIA Nitelikleri: Özellikle özel bileşenler için öğelerin rolü, durumu ve özellikleri hakkında ek bilgi sağlamak için ARIA niteliklerini kullanın.
- Klavye Navigasyonu: Tüm etkileşimli öğelerin klavye navigasyonu ile erişilebilir olduğundan emin olun.
- Renk Kontrastı: Metnin az gören kullanıcılar için okunabilir olmasını sağlamak için yeterli renk kontrastı kullanın.
- Ekran Okuyucu Uyumluluğu: Görme engelli kullanıcılar için anlamlı ve anlaşılır bir deneyim sağladıklarından emin olmak için bileşenlerinizi bir ekran okuyucu ile test edin.
Örnek: `getByRole` ile Erişilebilirliği Test Etme
// MyAccessibleComponent.js
import React from 'react';
function MyAccessibleComponent() {
return (
);
}
export default MyAccessibleComponent;
// MyAccessibleComponent.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import MyAccessibleComponent from './MyAccessibleComponent';
describe('MyAccessibleComponent', () => {
it('renders an accessible button with the correct aria-label', () => {
render( );
const buttonElement = screen.getByRole('button', { name: 'Close' });
expect(buttonElement).toBeInTheDocument();
});
});
Açıklama:
screen.getByRole('button', { name: 'Close' }): Erişilebilir adı "Close" olan bir düğme öğesi bulmak içingetByRolekullanır. Bu, düğmenin ekran okuyucular için düzgün bir şekilde etiketlendiğinden emin olur.
10. Testi Geliştirme İş Akışınıza Entegre Edin
Test, geliştirme iş akışınızın bir sonradan düşünülmüş bir parçası değil, ayrılmaz bir parçası olmalıdır. Kod gönderildiğinde veya dağıtıldığında testleri otomatik olarak çalıştırmak için testlerinizi CI/CD ardışık düzeninize entegre edin. Bu, hataları erken yakalamanıza ve regresyonları önlemenize yardımcı olacaktır.
11. Yerelleştirme ve Uluslararasılaştırmayı (i18n) Göz Önünde Bulundurun
Küresel uygulamalar için, test sırasında yerelleştirme ve uluslararasılaştırmayı (i18n) göz önünde bulundurmak çok önemlidir. Bileşenlerinizin farklı dillerde ve yerel ayarlarda doğru şekilde oluşturulduğundan emin olun.
Örnek: Yerelleştirmeyi Test Etme
Yerelleştirme için `react-intl` veya `i18next` gibi bir kütüphane kullanıyorsanız, bileşenlerinizin doğru çevrilmiş metni gösterdiğini doğrulamak için testlerinizde yerelleştirme bağlamını mock'layabilirsiniz.
12. Yeniden Kullanılabilir Kurulum için Özel Render Fonksiyonları Kullanın
Daha büyük projelerde çalışırken, birden fazla testte aynı kurulum adımlarını tekrarladığınızı fark edebilirsiniz. Tekrarı önlemek için, ortak kurulum mantığını kapsayan özel render fonksiyonları oluşturun.
Örnek: Özel Render Fonksiyonu
// test-utils.js
import React from 'react';
import { render } from '@testing-library/react';
import { ThemeProvider } from 'styled-components';
import theme from './theme';
const AllTheProviders = ({ children }) => {
return (
{children}
);
}
const customRender = (ui, options) =>
render(ui, { wrapper: AllTheProviders, ...options })
// re-export everything
export * from '@testing-library/react'
// override render method
export { customRender as render }
// MyComponent.test.js
import React from 'react';
import { render, screen } from './test-utils'; // Özel render fonksiyonunu içe aktar
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('renders correctly with the theme', () => {
render( );
// Test mantığınız buraya
});
});
Bu örnek, bileşeni bir ThemeProvider ile saran özel bir render fonksiyonu oluşturur. Bu, temaya dayalı bileşenleri her testte ThemeProvider kurulumunu tekrarlamak zorunda kalmadan kolayca test etmenizi sağlar.
Sonuç
React Testing Library, bileşen testine güçlü ve kullanıcı merkezli bir yaklaşım sunar. Bu en iyi uygulamaları takip ederek, kullanıcı davranışına ve erişilebilirliğe odaklanan, bakımı kolay ve etkili testler yazabilirsiniz. Bu, küresel bir kitle için daha sağlam, güvenilir ve kapsayıcı React uygulamalarına yol açacaktır. Kullanıcı etkileşimlerini önceliklendirmeyi, uygulama detaylarını test etmekten kaçınmayı, erişilebilirliğe odaklanmayı ve testi geliştirme iş akışınıza entegre etmeyi unutmayın. Bu ilkeleri benimseyerek, dünya çapındaki kullanıcıların ihtiyaçlarını karşılayan yüksek kaliteli React uygulamaları oluşturabilirsiniz.
Önemli Çıkarımlar:
- Kullanıcı Etkileşimlerine Odaklanın: Bileşenleri bir kullanıcının onlarla etkileşime gireceği şekilde test edin.
- Erişilebilirliği Önceliklendirin: Bileşenlerinizin engelli kullanıcılar için erişilebilir olduğundan emin olun.
- Uygulama Detaylarından Kaçının: İç state'i veya fonksiyon çağrılarını test etmeyin.
- Açık ve Öz Testler Yazın: Testlerinizi anlaşılması ve bakımı kolay hale getirin.
- Testi İş Akışınıza Entegre Edin: Testlerinizi otomatikleştirin ve düzenli olarak çalıştırın.
- Küresel Kitleleri Göz Önünde Bulundurun: Bileşenlerinizin farklı dillerde ve yerel ayarlarda iyi çalıştığından emin olun.