React Native Uygulamalarında Birim Testi

Yayınlanan: 2022-03-10
Kısa özet ↬ Birim testi, yazılım geliştirme sürecinin ayrılmaz bir parçası haline geldi. Yazılım bileşenlerinin test edildiği test seviyesidir. Bu öğreticide, bir React Native uygulamasının birimlerini nasıl test edeceğinizi öğreneceksiniz.

React Native, mobil uygulamalar oluşturmak için en yaygın kullanılan çerçevelerden biridir. Bu eğitim, oluşturdukları React Native uygulamalarını test etmeye başlamak isteyen geliştiricilere yöneliktir. Jest test çerçevesinden ve Enzyme'den yararlanacağız.

Bu makalede, test etmenin temel ilkelerini öğreneceğiz, bir uygulamayı test etmek için çeşitli kitaplıkları keşfedeceğiz ve bir React Native uygulamasının birimlerinin (veya bileşenlerinin) nasıl test edileceğini göreceğiz. Bir React Native uygulamasıyla çalışarak test bilgimizi pekiştireceğiz.

Not: Temel JavaScript ve React Native bilgisi, bu eğitimde çalışırken büyük fayda sağlayacaktır.

Birim Testi Nedir?

Birim testi, yazılımın tek tek bileşenlerinin test edildiği test düzeyidir. Bunu, her bileşenin beklendiği gibi çalışmasını sağlamak için yapıyoruz. Bileşen, yazılımın test edilebilir en küçük parçasıdır.

Örneklemek için, bir Button bileşeni oluşturalım ve bir birim testi simüle edelim:

 import React from 'react'; import { StyleSheet, Text, TouchableOpacity } from 'react-native'; function AppButton({ onPress }) { return ( <TouchableOpacity style={[styles.button, { backgroundColor: colors[color] }]} onPress={onPress} > <Text style={styles.text}>Register</Text> </TouchableOpacity> ); } const styles = StyleSheet.create({ button: { backgroundColor: red; borderRadius: 25, justifyContent: 'center', alignItems: 'center', }, text: { color: #fff } }) export default AppButton;

Bu Button bileşeninde metin ve onPress işlevi vardır. Birim testinin ne hakkında olduğunu görmek için bu bileşeni test edelim.

İlk olarak Button.test.js adında bir test dosyası oluşturalım:

 it('renders correctly across screens', () => { const tree = renderer.create(<Button />).toJSON(); expect(tree).toMatchSnapshot(); });

Burada, Button bileşenimizin uygulamanın tüm ekranlarında olması gerektiği gibi işlenip işlenmediğini test ediyoruz. Birim testinin amacı şudur: Bir uygulamanın bileşenlerini gerektiği gibi çalıştıklarından emin olmak için test etmek.

React Native Uygulamalarında Birim Testi

Bir React Native uygulaması, bazıları aşağıdaki gibi çeşitli araçlarla test edilebilir:

  • Web Sürücüsü
    Node.js uygulamalarına yönelik bu açık kaynaklı test aracı, React Native uygulamalarını test etmek için de kullanılır.
  • Kâbus
    Bu, tarayıcıdaki test işlemlerini otomatikleştirir. Belgelere göre, "amaç, kullanıcı eylemlerini taklit eden birkaç basit yöntemi ( goto , type ve click gibi), derinlemesine iç içe geçmiş geri aramalar yerine her komut dosyası bloğu için senkronize hisseden bir API ile ortaya çıkarmaktır."
  • Alay
    Bu, piyasadaki en popüler test kitaplıklarından biridir ve bugün üzerinde duracağımız kitaplıktır. React gibi, Facebook tarafından sürdürülür ve maksimum performans için "sıfır yapılandırma" kurulumu sağlamak üzere yapılmıştır.
  • moka
    Mocha, React ve React Native uygulamalarını test etmek için popüler bir kütüphanedir. Kurulumu ve kullanımı ne kadar kolay ve ne kadar hızlı olduğu için geliştiriciler için tercih edilen bir test aracı haline geldi.
  • Yasemin
    Belgelerine göre Jasmine, JavaScript kodunu test etmek için davranış odaklı bir geliştirme çerçevesidir.
Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

Jest ve Enzim'e Giriş

Belgelerine göre, “Jest, sadeliğe odaklanan keyifli bir JavaScript test çerçevesidir”. Sıfır konfigürasyon ile çalışır. Kurulumun ardından (npm veya Yarn gibi bir paket yöneticisi kullanılarak), Jest başka kurulum gerekmeden kullanıma hazırdır.

Enzyme, React Native uygulamaları için bir JavaScript test çerçevesidir. (React Native yerine React ile çalışıyorsanız, bir kılavuz mevcuttur.) Uygulamamızın çıktı birimlerini test etmek için Enzyme kullanacağız. Bununla, uygulamanın çalışma zamanını simüle edebiliriz.

Projemizi kurarak başlayalım. GitHub'da Done With It uygulamasını kullanacağız. Bu bir React Native uygulama pazarıdır. Klonlayarak başlayın, klasöre gidin ve npm için aşağıdakileri çalıştırarak paketleri kurun…

 npm install

… veya bu İplik için:

 yarn install

Bu komut uygulamamızdaki tüm paketleri kuracaktır. Bu yapıldıktan sonra, aşağıda ele alınan anlık görüntüleri kullanarak uygulamamızın UI tutarlılığını test edeceğiz.

Anlık Görüntüler ve Jest Yapılandırması

Bu bölümde, anlık görüntüleri Jest kullanarak test ederek kullanıcı dokunuşlarını ve uygulama bileşenlerinin kullanıcı arayüzünü test edeceğiz.

Bunu yapmadan önce Jest ve bağımlılıklarını kurmamız gerekiyor. Jest for Expo React Native'i yüklemek için aşağıdaki komutu çalıştırın:

 yarn add jest-expo --dev

Bu, uygulamamızın dizinine jest-expo yükler. Ardından, bir test betiğine sahip olmak için package.json dosyamızı güncellememiz gerekiyor:

 "scripts": { "test" "jest" }, "jest": { "preset": "jest-expo" }

Bu komutu ekleyerek Jest'e uygulamamıza hangi paketi nereye kayıt edeceğini söylüyoruz.

Sırada, Jest'in kapsamlı bir test yapmasına yardımcı olacak diğer paketleri uygulamamıza eklemek var. npm için bunu çalıştırın…

 npm i react-test-renderer --save-dev

… ve Yarn için bu:

 yarn add react-test-renderer --dev

Hala package.json dosyamızda yapmamız gereken küçük bir konfigürasyon var. Expo React Native'in belgelerine göre, bir kaynak dosya bir testle eşleştiğinde (yani bir test yapılırsa ve projenin node modules benzer bir dosya bulunursa) testlerin Jest'te çalışmasını engelleyen bir transformIgnorePattern yapılandırması eklememiz gerekir.

 "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*)" ] }

Şimdi ilk testimizi yazmak için App.test.js adında yeni bir dosya oluşturalım. App ağacında bir alt öğe olup olmadığını test edeceğiz:

 import React from "react"; import renderer from "react-test-renderer"; import App from "./App.js" describe("<App />", () => { it('has 1 child', () => { const tree = renderer.create(<App />).toJSON(); expect(tree.children.length).toBe(1); }); });

Şimdi, yarn test veya npm eşdeğerini çalıştırın. App.js tek bir alt öğesi varsa, komut satırı arayüzünde onaylanacak olan testimiz geçmelidir.

Yukarıdaki kodda, Expo için testlerimizi oluşturan React ve react-test-renderer öğelerini içe aktardık. <App /> bileşen ağacını JSON'a dönüştürdük ve ardından Jest'ten JSON'da döndürülen alt bileşen sayısının beklediğimize eşit olup olmadığını görmesini istedik.

Daha Fazla Anlık Görüntü Testi

David Adeneye'nin belirttiği gibi:

“Anlık görüntü testi, bir web uygulamasının kullanıcı arayüzünün (UI) beklenmedik şekilde değişmemesini sağlar. Bileşenin kodunu herhangi bir zamanda yakalar, böylece bileşeni bir durumdaki diğer olası durumlarla karşılaştırabiliriz."

Bu, özellikle bir proje birçok bileşende kullanılan global stilleri içerdiğinde yapılır. App.js kullanıcı arayüzü tutarlılığını test etmesi için bir anlık görüntü testi yazalım:

 it('renders correctly across screens', () => { const tree = renderer.create( ).toJSON(); expect(tree).toMatchSnapshot(); }); it('renders correctly across screens', () => { const tree = renderer.create( ).toJSON(); expect(tree).toMatchSnapshot(); });

Bunu daha önce yazdığımız testlere ekleyin ve ardından yarn test (veya npm eşdeğerini) çalıştırın. Testimiz geçerse şunu görmeliyiz:

 PASS src/App.test.js √ has 1 child (16ms) √ renders correctly (16ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 1 total Time: 24s

Bu bize testlerimizin geçtiğini ve aldıkları süreyi söyler. Testler geçerse sonucunuz benzer görünecektir.

Jest'teki bazı işlevlerle alay etmeye devam edelim.

API Çağrılarını Alay Etmek

Jest'in belgelerine göre:

Sahte işlevler, bir işlevin gerçek uygulamasını silerek, işleve yapılan çağrıları (ve bu çağrılarda iletilen parametreleri) yakalayarak, "yeni" ile örneklendiğinde yapıcı işlevlerin örneklerini yakalayarak ve teste izin vererek kod arasındaki bağlantıları test etmenize olanak tanır. dönüş değerlerinin zaman yapılandırması.

Basitçe söylemek gerekirse, sahte, bir nesnenin veya işlevin, bu işlevin gerçek işleyişi olmayan bir kopyasıdır. Bu işlevi taklit eder.

Sahteler, uygulamaları pek çok şekilde test etmemize yardımcı olur, ancak asıl faydası, bağımlılık ihtiyacımızı azaltmalarıdır.

Mocks genellikle iki yoldan biriyle gerçekleştirilebilir. Biri, test edilecek koda enjekte edilen sahte bir işlev oluşturmaktır. Diğeri, bileşene bağlı paketi veya bağımlılığı geçersiz kılan bir sahte işlev yazmaktır.

Çoğu kuruluş ve geliştirici, bazı bileşenleri test etmek için işlevselliği taklit eden ve sahte veriler kullanan manuel modeller yazmayı tercih eder.

React Native, global nesnede fetch içerir. Birim testimizde gerçek API çağrıları yapmaktan kaçınmak için onlarla alay ediyoruz. Aşağıda, React Native'de ve bağımlılığa gerek kalmadan API çağrılarımızın çoğu olmasa da tümü ile alay etmenin bir yolu bulunmaktadır:

 global.fetch = jest.fn(); // mocking an API success response once fetch.mockResponseIsSuccess = (body) => { fetch.mockImplementationForOnce ( () => Promise.resolve({json: () => Promise.resolve(JSON.parse(body))}) ); }; // mocking an API failure response for once fetch.mockResponseIsFailure = (error) => { fetch.mockImplementationForOnce( () => Promise.reject(error) ); };

Burada bir kere API getirmeye çalışan bir fonksiyon yazdık. Bunu yaptıktan sonra bir söz verir ve çözüldüğünde gövdeyi JSON'da döndürür. Başarısız bir getirme işlemi için sahte yanıta benzer - bir hata döndürür.

Aşağıda, uygulamamızın bir product nesnesi içeren ve bilgileri props olarak döndüren product bileşeni bulunmaktadır.

 import React from 'react'; const Product = () => { const product = { name: 'Pizza', quantity: 5, price: '$50' } return ( <> <h1>Name: {product.name}</h1> <h1>Quantity: {product.quantity}</h1> <h1>Price: {product.price}</h1> </> ); } export default Product;

Ürünümüzün tüm bileşenlerini test etmeye çalıştığımızı düşünelim. Veritabanımıza doğrudan erişmek uygun bir çözüm değildir. İşte burada alaylar devreye giriyor. Aşağıdaki kodda, bileşendeki nesneleri tanımlamak için Jest kullanarak ürünün bir bileşeniyle alay etmeye çalışıyoruz.

 describe("", () => { it("accepts products props", () => { const wrapper = mount(<Customer product={product} />); expect(wrapper.props().product).toEqual(product); }); it("contains products quantity", () => { expect(value).toBe(3); }); });

Yapılmasını istediğimiz testleri dikte etmek için Jest'ten describe kullanıyoruz. İlk testte, geçtiğimiz nesnenin alay ettiğimiz sahneye eşit olup olmadığını kontrol ediyoruz.

İkinci testte, bir ürün olduğundan ve taklitlerimizle eşleştiğinden emin olmak için customer aksesuarlarını geçiyoruz. Bunu yaparken, ürünümüzün tüm bileşenlerini test etmek zorunda değiliz ve ayrıca kodumuzdaki hataları da önlemiş oluyoruz.

Harici API İstekleriyle Alay Etmek

Şimdiye kadar, uygulamamızdaki diğer öğelerle API çağrıları için testler yapıyorduk. Şimdi harici bir API çağrısı ile alay edelim. Axios'u kullanacağız. Bir API'ye yapılan harici bir çağrıyı test etmek için isteklerimizle dalga geçmeli ve aldığımız yanıtları yönetmeliyiz. Axios ile alay etmek için axios-mock-adapter kullanacağız. Öncelikle, aşağıdaki komutu çalıştırarak axios-mock-adapter kurmamız gerekiyor:

 yarn add axios-mock-adapter

Yapılacak bir sonraki şey, alaylarımızı oluşturmaktır:

 import MockAdapter from 'axios-mock-adapter'; import Faker from 'faker' import ApiClient from '../constants/api-client'; import userDetails from 'jest/mockResponseObjects/user-objects'; let mockApi = new MockAdapter(ApiClient.getAxiosInstance()); let validAuthentication = { name: Faker.internet.email(), password: Faker.internet.password() mockApi.onPost('requests').reply(config) => { if (config.data === validAuthentication) { return [200, userDetails]; } return [400, 'Incorrect username and password']; });

Burada, ApiClient çağırıyoruz ve kullanıcının kimlik bilgileriyle alay etmek için ona bir Axios örneği gönderiyoruz. E-posta adresi ve şifre gibi sahte kullanıcı verileri oluşturmak için faker.js adlı bir paket kullanıyoruz.

Sahte, API'den beklediğimiz gibi davranır. İstek başarılı olursa, OK için 200 durum koduyla bir yanıt alırız. Ve sunucuya, JSON ile “Yanlış kullanıcı adı ve şifre” mesajıyla gönderilecek olan kötü bir istek için 400 durum kodunu alacağız.

Artık maketimiz hazır olduğuna göre, harici bir API isteği için bir test yazalım. Daha önce olduğu gibi, anlık görüntüleri kullanacağız.

 it('successful sign in with correct credentials', async () => { await store.dispatch(authenticateUser('[email protected]', 'password')); expect(getActions()).toMatchSnapshot(); }); it('unsuccessful sign in with wrong credentials', async () => { await store.dispatch(authenticateUser('[email protected]', 'wrong credential')) .catch((error) => { expect(errorObject).toMatchSnapshot(); });

Burada, girişlerimizi tutmak için yerel JavaScript zaman async await bekleme özelliğini kullanarak doğru kimlik bilgileriyle başarılı bir oturum açmayı test ediyoruz. Bu arada, Jest'in authenticateUser işlevi, isteğin kimliğini doğrular ve önceki anlık görüntülerimizle eşleştiğinden emin olur. Ardından, e-posta adresi veya şifre gibi yanlış kimlik bilgileri olması durumunda başarısız bir oturum açma testi yaparız ve yanıt olarak bir hata göndeririz.

Şimdi, yarn test veya npm test çalıştırın. Tüm sınavların geçeceğine eminim.

Bir durum yönetimi kitaplığındaki bileşenlerin nasıl test edileceğini görelim, Redux.

Anlık Görüntüleri Kullanarak Redux Eylemlerini ve Düşürücüleri Test Etme

Redux'un React uygulamaları için en yaygın kullanılan durum yöneticilerinden biri olduğu inkar edilemez. Redux'taki işlevlerin çoğu, bir uygulamanın durumunda bir değişikliği tetiklemek için kullanılan Redux deposunun bir işlevi olan bir dispatch içerir. Redux'u test etmek zor olabilir çünkü Redux'un actions boyut ve karmaşıklık açısından hızla büyür. Jest anlık görüntüleri ile bu daha kolay hale gelir. Redux ile yapılan çoğu test iki şeye iner:

  • actions test etmek için redux-mock-store oluşturuyoruz ve eylemleri gönderiyoruz.
  • Redüktörleri test etmek için reducer içe aktarır ve ona bir durum ve eylem nesnesi iletiriz.

Aşağıda, anlık görüntüler içeren bir Redux testi bulunmaktadır. SIGN-IN sırasında kullanıcının kimliğini doğrulayarak ve LOGOUT eyleminin user azaltıcı tarafından nasıl işlendiğini görerek gönderilen eylemleri test edeceğiz.

 import mockStore from 'redux-mock-store'; import { LOGOUT } from '../actions/logout'; import User from '../reducers/user'; import { testUser } from 'jest/mock-objects'; describe('Testing the sign in authentication', () => { const store = mockStore(); it('user attempts with correct password and succeeds', async () => { await store.dispatch(authenticateUser('[email protected]', 'password')); expect(store.getActions()).toMatchSnapshot(); }); }); describe('Testing reducers after user LOGS OUT', () => { it('user is returned back to initial app state', () => { expect(user(testUser, { type: LOGOUT })).toMatchSnapshot(); }); });

İlk testte, oturum açma kimlik doğrulamasını açıklıyor ve bir sahte mağaza oluşturuyoruz. Bunu önce Redux'tan bir mockStore içe aktararak ve ardından bir kullanıcıyla alay etmemize yardımcı olması için testUser adlı bir yöntemi içe aktararak yaparız. Ardından, kullanıcının anlık görüntü mağazamızdakilerle eşleşen bir e-posta adresi ve şifre kullanarak uygulamada başarılı bir şekilde oturum açtığını test ederiz. Bu nedenle, anlık görüntü, kullanıcının girdiği nesnelerin bir test her çalıştırıldığında eşleşmesini sağlar.

İkinci testte, kullanıcının oturumu ne zaman kapattığını test ediyoruz. İndirgeyici anlık görüntümüz, bir kullanıcının oturumu kapattığını doğruladığında, uygulamanın ilk durumuna geri döner.

Ardından, yarn test çalıştırarak test ediyoruz. Testler geçtiyse, aşağıdaki sonucu görmeliyiz:

 PASS src/redux/actions.test.js √ user attempts with correct password and succeeds (23ms) √ user is returned back to initial app state (19ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 2 total Time: 31s

Çözüm

Jest ile React Native uygulamalarını test etmek, özellikle de global stillerden bağımsız olarak kullanıcı arayüzünün tutarlı kalmasını sağlayan anlık görüntülerle hiç bu kadar kolay olmamıştı. Ayrıca Jest, uygulamamızdaki belirli API çağrıları ve modülleri ile alay etmemizi sağlar. Bir React Native uygulamasının bileşenlerini test ederek bunu daha da ileri götürebiliriz.

Diğer Kaynaklar

  • “React Native Uygulamalarını Jest ile Test Etmek İçin Pratik Bir Kılavuz”, David Adeneye, Smashing Magazine
  • jest belgeleri
  • “Jest ile Test Etme”, Expo React Native belgeleri
  • “Jest ile Yerli Tepkiyi Test Etmeyi Öğrenmek”, Jason Gaare