Natiivimoduulien ja asynkronisen koodin mockaaminen
Mockatkaa expo-location ja muut natiivimoduulit Jestin asetustiedostoissa, käyttäkää jest.fn()-funktiota callbackeihin ja testatkaa asynkronisia työnkulkuja waitFor- ja findBy-kyselyillä.
Natiivimoduulien ja asynkronisen koodin mockaaminen on ilmainen React Native Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu React Native Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. React Native Academy-kurssilla on yhteensä 4 oppituntia.
Natiivimoduulien ongelma Jestissä
Jest suoritetaan Node.js-ympäristössä, ei oikealla laitteella. Kun komponentti tuo käyttöön natiivimoduulin, kuten expo-camera tai @react-native-async-storage/async-storage, Jest ei voi suorittaa natiivikoodia, koska käytettävissä ei ole iOS- tai Android-ajoympäristöä.
Tämä aiheuttaa testien epäonnistumisen esimerkiksi virheillä 'jest-environment-jsdom is not supported' tai 'Cannot read property of undefined'. Ratkaisu on mokata natiivimoduulit eli korvata ne vain JavaScriptiä käyttävillä valeobjekteilla, jotka toimivat testeissä ennakoitavasti.
Manuaaliset mokat __mocks__-kansiossa
Voitte luoda mille tahansa moduulille manuaalisen mokan luomalla tiedoston node_modules-kansion vieressä olevaan __mocks__-hakemistoon. Jest käyttää tätä mokaa automaattisesti aina, kun moduuli tuodaan käyttöön testitiedostoissa.
Luokaa esimerkiksi __mocks__/@react-native-async-storage/async-storage.js, joka sisältää tiedot muistiin tallentavan valeimplementaation. Expo- ja React Native -yhteisöt ylläpitävät virallisia mokapaketteja yleisille natiivimoduuleille.
// __mocks__/@react-native-async-storage/async-storage.js
const storage = {};
export default {
getItem: jest.fn((key) => Promise.resolve(storage[key] ?? null)),
setItem: jest.fn((key, value) => {
storage[key] = value;
return Promise.resolve();
}),
removeItem: jest.fn((key) => {
delete storage[key];
return Promise.resolve();
}),
clear: jest.fn(() => {
Object.keys(storage).forEach((k) => delete storage[k]);
return Promise.resolve();
}),
getAllKeys: jest.fn(() => Promise.resolve(Object.keys(storage))),
};Virallisen mokapaketin käyttäminen
@react-native-async-storage/async-storage sisältää oman virallisen Jest-mokansa polussa @react-native-async-storage/async-storage/jest/async-storage-mock. Rekisteröikää se Jestin asetustiedostossa, jotta voitte käyttää sitä kaikissa testeissä ilman mokan kirjoittamista itse.
Samoin react-native mokkaa monia sisäänrakennettuja komponentteja, kun käytössä on react-native-Jest-esiasetus. Tarkistakaa kunkin kirjaston dokumentaatiosta sen suosittelema Jest-mokan määritys.
// jest.config.js
module.exports = {
preset: 'jest-expo',
moduleNameMapper: {
'@react-native-async-storage/async-storage':
'@react-native-async-storage/async-storage/jest/async-storage-mock',
},
setupFilesAfterFramework: [
'@testing-library/jest-native/extend-expect',
],
};expo-locationin mokaaminen
expo-*-nimiavaruuden moduulit edellyttävät usein natiivien käyttöoikeuksien lisäksi GPS-laitteistoa. Mokatkaa ne jest.mock()-kutsulla testitiedoston alussa, jotta voitte palauttaa hallittuja vale arvoja ilman laitteen käyttöä.
Palauttakaa asynkronisista metodeista ratkaistuja Promiseja, jotta niiden muoto vastaa todellista APIa. Paluuarvoja hallitsemalla voitte testata kaikki haarat: mitä tapahtuu, kun käyttöoikeus myönnetään tai evätään tai kun GPS palauttaa tietyt koordinaatit.
jest.mock('expo-location', () => ({
requestForegroundPermissionsAsync: jest.fn(),
getCurrentPositionAsync: jest.fn(),
PermissionStatus: { GRANTED: 'granted', DENIED: 'denied' },
}));
import * as Location from 'expo-location';
it('shows coordinates when permission is granted', async () => {
Location.requestForegroundPermissionsAsync
.mockResolvedValue({ status: 'granted' });
Location.getCurrentPositionAsync
.mockResolvedValue({ coords: { latitude: 37.78, longitude: -122.43 } });
const { findByText } = render(<LocationScreen />);
await findByText('37.78, -122.43');
});Fetch API:n mokaaminen
Kun komponentit tekevät HTTP-pyyntöjä fetch-funktiolla, mokatkaa testeissä globaali fetch-funktio, jotta verkkopyynnöt eivät kohdistu oikeisiin palvelimiin. Korvatkaa fetch hallitulla toteutuksella käyttämällä jest.spyOn(global, 'fetch').mockResolvedValue()-kutsua.
Palauttakaa mokattu Response-tyyppinen objekti, jonka json()-metodi palauttaa testitiedot. Nollatkaa moka afterEach-lohkossa, jotta jokainen testi alkaa puhtaasta tilanteesta.
beforeEach(() => {
global.fetch = jest.fn();
});
afterEach(() => {
jest.restoreAllMocks();
});
it('displays fetched posts in a list', async () => {
const mockPosts = [{ id: '1', title: 'Hello World' }];
global.fetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockPosts),
});
const { findByText } = render(<PostFeed />);
await findByText('Hello World');
expect(global.fetch).toHaveBeenCalledWith(
'https://api.example.com/posts'
);
});Axioksen mokaaminen
Jos sovelluksenne käyttää Axiosta, asentakaa axios-mock-adapter sieppaamaan pyynnöt ja palauttamaan mokatut vastaukset. Käärikää Axios-instanssi adapteriin, määrittäkää mokatut vastaukset päätepistekohtaisesti ja nollatkaa adapteri testien välillä.
Tämä lähestymistapa on siistimpi kuin koko axios-moduulin mokaaminen, koska sen avulla voitte testata tiettyjä URL-malleja ja HTTP-metodeja toisistaan riippumatta.
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
const mock = new MockAdapter(axios);
afterEach(() => mock.reset());
it('fetches and displays user profile', async () => {
mock.onGet('/api/users/123').reply(200, {
id: '123',
name: 'Alice',
email: 'alice@test.com',
});
const { findByText } = render(<ProfileScreen userId='123' />);
await findByText('Alice');
await findByText('alice@test.com');
});Asynkronisten hookien testaaminen renderHookilla
RNTL tarjoaa renderHook-apuohjelman mukautettujen hookien testaamiseen erillään. Se renderöi minimaalisen komponentin, joka kutsuu hookia, ja tarjoaa hookin palautusarvon käytettäväksi. Näin voitte testata hookin logiikkaa sitomatta sitä tiettyyn käyttöliittymäkomponenttiin.
Dataa hakevien asynkronisten hookien tapauksessa kääritkää tilamuutokset act-kutsuun ja käyttäkää waitFor-kutsua odottamaan asynkronisen toiminnon valmistumista ennen väitteen tekemistä.
import { renderHook, act, waitFor } from '@testing-library/react-native';
import { useUserProfile } from '../src/hooks/useUserProfile';
it('fetches the user profile on mount', async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ id: '1', name: 'Bob' }),
});
const { result } = renderHook(() => useUserProfile('1'));
// Initially loading
expect(result.current.loading).toBe(true);
// Wait for the fetch to complete
await waitFor(() => expect(result.current.loading).toBe(false));
expect(result.current.user?.name).toBe('Bob');
});AsyncStoragen testaaminen testeissä
Kun testaatte komponentteja, jotka lukevat tietoja AsyncStorage-säilöstä tai kirjoittavat siihen, teidän on hallittava säilön palauttamaa sisältöä eri alkutilojen testaamiseksi. Mokakaa säilö ennen testiä ja varmistakaa kirjoituskutsut vuorovaikutuksen jälkeen.
Tyhjentäkää mokan kutsuhistoria beforeEach-lohkossa käyttämällä jest.clearAllMocks()-kutsua, jotta yhden testin säilölukemat eivät vaikuta seuraavaan testiin. Nollatkaa muistissa oleva säilökartta, jos manuaalinen mokanne säilyttää tietoja kutsujen välillä.
import AsyncStorage from '@react-native-async-storage/async-storage';
it('loads dark mode preference on mount', async () => {
// Arrange: storage returns 'dark' for theme key
AsyncStorage.getItem.mockResolvedValue('dark');
const { findByText } = render(<SettingsScreen />);
// Assert theme applied
await findByText('Dark Mode: ON');
expect(AsyncStorage.getItem).toHaveBeenCalledWith('theme');
});
it('saves the new theme when toggle is pressed', async () => {
AsyncStorage.getItem.mockResolvedValue('light');
const { getByTestId, waitFor } = render(<SettingsScreen />);
fireEvent(getByTestId('theme-toggle'), 'valueChange', true);
await waitFor(() =>
expect(AsyncStorage.setItem).toHaveBeenCalledWith('theme', 'dark')
);
});waitFor- ja findBy-toimintojen avulla testaaminen
waitFor(callback) kutsuu callback-funktiota toistuvasti, kunnes se ei enää heitä poikkeusta, määritettävissä olevaan aikakatkaisuun asti (oletusarvo on 1000 ms). Käyttäkää sitä, kun käyttöliittymä päivittyy asynkronisen toiminnon jälkeen, jonka ajoitusta ei voida ennustaa.
findBy*-kyselyt, kuten findByText, ovat lyhyempi syntaksi rakenteelle waitFor(() => getByText(...)). Käyttäkää findBy-kyselyitä yksittäisille elementeille ja waitFor-kutsua monimutkaisiin, useita elementtejä tai ehtoja koskeviin väitteisiin.
import { render, fireEvent, waitFor } from '@testing-library/react-native';
it('shows error message when API returns 400', async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: false,
status: 400,
json: () => Promise.resolve({ message: 'Invalid email' }),
});
const { getByRole, findByText } = render(<SignUpForm />);
fireEvent.press(getByRole('button', { name: 'Create Account' }));
// Wait for the error to appear after the API response
expect(await findByText('Invalid email')).toBeTruthy();
// Alternatively:
await waitFor(() => {
expect(getByText('Invalid email')).toBeTruthy();
expect(getByRole('button', { name: 'Create Account' })).not.toBeDisabled();
});
});Ajastinten mokaaminen viivästetyille syötteille
Hakukentät viivästyttävät usein API-kutsuja – ne odottavat, että käyttäjä lopettaa kirjoittamisen, ennen kuin käynnistävät pyynnön. Testatkaa viivästettyä toimintaa käyttämällä jest.useFakeTimers()-kutsua ja hallitsemalla aikaa jest.advanceTimersByTime(ms)-kutsulla sen sijaan, että odottaisitte todellisen viiveen kulumista.
Kutsukaa jest.useRealTimers() afterEach-lohkossa palauttaaksenne oikeat ajastinfunktiot muille testeille, jotka saattavat käyttää niitä.
it('triggers search after 500ms debounce', async () => {
jest.useFakeTimers();
const mockSearch = jest.fn().mockResolvedValue([]);
const { getByPlaceholderText } = render(<DebouncedSearch onSearch={mockSearch} />);
fireEvent.changeText(getByPlaceholderText('Search...'), 'react');
// Not yet called — debounce delay not elapsed
expect(mockSearch).not.toHaveBeenCalled();
// Advance time past the debounce window
await act(async () => {
jest.advanceTimersByTime(500);
});
expect(mockSearch).toHaveBeenCalledWith('react');
jest.useRealTimers();
});Testien asetustiedostot globaaleille mokille
Sen sijaan että toistaisitte saman mokan määrityksen jokaisessa testitiedostossa, sijoittakaa globaalit mokat Jestin asetustiedostoon, joka määritetään asetuksella setupFilesAfterFramework. Tämä suoritetaan kerran ennen kaikkia testejä ja rekisteröi mokat globaalisti.
Yleisiä globaaleja mokia ovat natiivimoduulit (AsyncStorage, kamera ja sijainti), analytiikkakirjastot (verkkokutsujen estämiseksi) sekä suorituskyvyn seuranta. Pitäkää asetustiedosto suppeana – lisätkää vain mokat, joita tarvitaan useimmissa testeissä.
// jest-setup.ts (referenced in jest.config.js setupFilesAfterFramework)
import '@testing-library/jest-native/extend-expect';
// Mock AsyncStorage globally
jest.mock('@react-native-async-storage/async-storage',
() => require('@react-native-async-storage/async-storage/jest/async-storage-mock')
);
// Mock analytics to avoid network calls in tests
jest.mock('@segment/analytics-react-native', () => ({
createClient: jest.fn(() => ({ track: jest.fn(), identify: jest.fn() })),
}));
// Silence console.error for expected React warnings in tests
const consoleError = console.error;
console.error = (...args) => {
if (String(args[0]).includes('Warning:')) return;
consoleError(...args);
};Pikatarkistus
Testatkaa, kuinka hyvin hallitsette tämän oppitunnin React Native Mobile Development -käsitteet.
Oppitunnin yhteenveto
Tässä oppitunnissa opitte: mokaamaan natiivimoduuleja jest.mock()-kutsulla ja manuaalisilla mokatiedostoilla __mocks__-hakemistossa, mokaamaan HTTP-kutsuja jest.fn()-kutsulla tai axios-mock-adapterilla hallittua verkkotestausta varten sekä testaamaan asynkronisia virtoja waitFor- ja findBy-kyselyillä sekä valetuilla ajastimilla. Seuraavaksi kirjoitamme Maestrolla päästä päähän -testejä, jotka ohjaavat oikeaa sovellusta laitteella.
Opi JavaScript tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 30
- Oppitunnit
- 120
Usein kysytyt kysymykset
Onko oppitunti ”Natiivimoduulien ja asynkronisen koodin mockaaminen” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa React Native Academy-oppimispolun 3 oppituntia, myös oppitunnin “Natiivimoduulien ja asynkronisen koodin mockaaminen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. React Native Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Natiivimoduulien ja asynkronisen koodin mockaaminen”?
Mockatkaa expo-location ja muut natiivimoduulit Jestin asetustiedostoissa, käyttäkää jest.fn()-funktiota callbackeihin ja testatkaa asynkronisia työnkulkuja waitFor- ja findBy-kyselyillä. Harjoittelet React Native Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni React Native Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin React Native Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”Natiivimoduulien ja asynkronisen koodin mockaaminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä React Native Academy-oppitunnilla?
Kyllä. Jokainen React Native Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Jestin määrittäminen React Native -projektiin
- Komponenttien renderöinti React Native Testing Librarylla
- Tapahtumien käynnistäminen ja käyttäjän vuorovaikutuksen testaaminen
- Natiivimoduulien ja asynkronisen koodin mockaaminen