Latviešu

Apgūstiet uzlabotas Jest testēšanas metodes, lai izveidotu uzticamāku un uzturēšanai ērtāku programmatūru. Izpētiet tehnikas, piemēram, imitēšanu, momentuzņēmumu testēšanu, pielāgotus salīdzinātājus un citas, kas paredzētas globālām izstrādes komandām.

Jest: Uzlabotas testēšanas metodes robustai programmatūrai

Mūsdienu straujajā programmatūras izstrādes vidē koda bāzes uzticamības un stabilitātes nodrošināšana ir vissvarīgākā. Lai gan Jest ir kļuvis par de facto standartu JavaScript testēšanai, pāreja no pamata vienībtestiem paver jaunu pārliecības līmeni par jūsu lietojumprogrammām. Šajā rakstā aplūkotas uzlabotas Jest testēšanas metodes, kas ir būtiskas, lai izveidotu robustu programmatūru, apmierinot globālu izstrādātāju auditoriju.

Kāpēc neaprobežoties ar pamata vienībtestiem?

Pamata vienībtesti pārbauda atsevišķus komponentus izolēti. Tomēr reālās pasaules lietojumprogrammas ir sarežģītas sistēmas, kurās komponenti mijiedarbojas. Uzlabotas testēšanas metodes risina šīs sarežģītības, ļaujot mums:

Imitēšanas (Mocking) un novērotāju (Spies) apgūšana

Imitēšana (mocking) ir ļoti svarīga, lai izolētu testējamo vienību, aizstājot tās atkarības ar kontrolētiem aizstājējiem. Jest šim nolūkam nodrošina jaudīgus rīkus:

jest.fn(): Imitāciju (Mocks) un novērotāju (Spies) pamats

jest.fn() izveido imitētu funkciju (mock function). Jūs varat sekot līdzi tās izsaukumiem, argumentiem un atgrieztajām vērtībām. Tas ir pamatelements sarežģītākām imitēšanas stratēģijām.

Piemērs: Funkciju izsaukumu izsekošana

// component.js
export const fetchData = () => {
  // Imitē API izsaukumu
  return Promise.resolve({ data: 'some data' });
};

export const processData = async (fetcher) => {
  const result = await fetcher();
  return `Processed: ${result.data}`;
};

// component.test.js
import { processData } from './component';

test('should process data correctly', async () => {
  const mockFetcher = jest.fn().mockResolvedValue({ data: 'mocked data' });
  const result = await processData(mockFetcher);
  expect(result).toBe('Processed: mocked data');
  expect(mockFetcher).toHaveBeenCalledTimes(1);
  expect(mockFetcher).toHaveBeenCalledWith();
});

jest.spyOn(): Novērošana bez aizvietošanas

jest.spyOn() ļauj novērot metodes izsaukumus esošam objektam, neaizstājot tā implementāciju. Ja nepieciešams, varat arī imitēt implementāciju.

Piemērs: Moduļa metodes novērošana

// logger.js
export const logInfo = (message) => {
  console.log(`INFO: ${message}`);
};

// service.js
import { logInfo } from './logger';

export const performTask = (taskName) => {
  logInfo(`Starting task: ${taskName}`);
  // ... uzdevuma loģika ...
  logInfo(`Task ${taskName} completed.`);
};

// service.test.js
import { performTask } from './service';
import * as logger from './logger';

test('should log task start and completion', () => {
  const logSpy = jest.spyOn(logger, 'logInfo');

  performTask('backup');

  expect(logSpy).toHaveBeenCalledTimes(2);
  expect(logSpy).toHaveBeenCalledWith('Starting task: backup');
  expect(logSpy).toHaveBeenCalledWith('Task backup completed.');

  logSpy.mockRestore(); // Svarīgi atjaunot sākotnējo implementāciju
});

Moduļu importu imitēšana

Jest moduļu imitēšanas iespējas ir plašas. Jūs varat imitēt veselus moduļus vai konkrētus eksportus.

Piemērs: Ārēja API klienta imitēšana

// api.js
import axios from 'axios';

export const getUser = async (userId) => {
  const response = await axios.get(`/api/users/${userId}`);
  return response.data;
};

// user-service.js
import { getUser } from './api';

export const getUserFullName = async (userId) => {
  const user = await getUser(userId);
  return `${user.firstName} ${user.lastName}`;
};

// user-service.test.js
import { getUserFullName } from './user-service';
import * as api from './api';

// Imitēt visu api moduli
jest.mock('./api');

test('should get full name using mocked API', async () => {
  // Imitēt konkrētu funkciju no imitētā moduļa
  api.getUser.mockResolvedValue({ id: 1, firstName: 'Ada', lastName: 'Lovelace' });

  const fullName = await getUserFullName(1);

  expect(fullName).toBe('Ada Lovelace');
  expect(api.getUser).toHaveBeenCalledTimes(1);
  expect(api.getUser).toHaveBeenCalledWith(1);
});

Automātiskā imitēšana pret manuālo imitēšanu

Jest automātiski imitē Node.js moduļus. ES moduļiem vai pielāgotiem moduļiem var būt nepieciešams jest.mock(). Lielākai kontrolei varat izveidot __mocks__ direktorijas.

Imitētās implementācijas

Jūs varat nodrošināt pielāgotas implementācijas savām imitācijām.

Piemērs: Imitēšana ar pielāgotu implementāciju

// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;

// calculator.js
import { add, subtract } from './math';

export const calculate = (operation, a, b) => {
  if (operation === 'add') {
    return add(a, b);
  } else if (operation === 'subtract') {
    return subtract(a, b);
  }
  return null;
};

// calculator.test.js
import { calculate } from './calculator';
import * as math from './math';

// Imitēt visu math moduli
jest.mock('./math');

test('should perform addition using mocked math add', () => {
  // Nodrošināt imitētu implementāciju 'add' funkcijai
  math.add.mockImplementation((a, b) => a + b + 10); // Pievienot 10 rezultātam
  math.subtract.mockReturnValue(5); // Imitēt arī atņemšanu

  const result = calculate('add', 5, 3);

  expect(math.add).toHaveBeenCalledWith(5, 3);
  expect(result).toBe(18); // 5 + 3 + 10

  const subResult = calculate('subtract', 10, 2);
  expect(math.subtract).toHaveBeenCalledWith(10, 2);
  expect(subResult).toBe(5);
});

Momentuzņēmumu testēšana: UI un konfigurācijas saglabāšana

Momentuzņēmumu testi ir jaudīga funkcija, kas fiksē jūsu komponentu vai konfigurāciju izvadi. Tie ir īpaši noderīgi UI testēšanai vai sarežģītu datu struktūru pārbaudei.

Kā darbojas momentuzņēmumu testēšana

Pirmo reizi, kad tiek palaists momentuzņēmuma tests, Jest izveido .snap failu, kas satur testētās vērtības serializētu attēlojumu. Nākamajās palaišanas reizēs Jest salīdzina pašreizējo izvadi ar saglabāto momentuzņēmumu. Ja tie atšķiras, tests neizdodas, brīdinot jūs par neparedzētām izmaiņām. Tas ir nenovērtējami, lai atklātu regresijas UI komponentos dažādos reģionos vai lokalizācijās.

Piemērs: React komponenta momentuzņēmuma izveide

Pieņemot, ka jums ir React komponents:

// UserProfile.js
import React from 'react';

const UserProfile = ({ name, email, isActive }) => (
  <div>
    <h2>{name}</h2>
    <p><strong>E-pasts:</strong> {email}</p>
    <p><strong>Statuss:</strong> {isActive ? 'Aktīvs' : 'Neaktīvs'}</p>
  </div>
);

export default UserProfile;

// UserProfile.test.js
import React from 'react';
import renderer from 'react-test-renderer'; // React komponentu momentuzņēmumiem
import UserProfile from './UserProfile';

test('renders UserProfile correctly', () => {
  const user = {
    name: 'Jane Doe',
    email: 'jane.doe@example.com',
    isActive: true,
  };
  const component = renderer.create(
    <UserProfile {...user} />
  );
  const tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

test('renders inactive UserProfile correctly', () => {
  const user = {
    name: 'John Smith',
    email: 'john.smith@example.com',
    isActive: false,
  };
  const component = renderer.create(
    <UserProfile {...user} />
  );
  const tree = component.toJSON();
  expect(tree).toMatchSnapshot('inactive user profile'); // Nosaukts momentuzņēmums
});

Pēc testu palaišanas Jest izveidos UserProfile.test.js.snap failu. Kad jūs atjaunināsiet komponentu, jums būs jāpārskata izmaiņas un, iespējams, jāatjaunina momentuzņēmums, palaižot Jest ar --updateSnapshot vai -u karodziņu.

Momentuzņēmumu testēšanas labākās prakses

Pielāgoti salīdzinātāji: Testu lasāmības uzlabošana

Jest iebūvētie salīdzinātāji ir plaši, bet dažreiz ir nepieciešams pārbaudīt specifiskus nosacījumus, kas nav ietverti. Pielāgoti salīdzinātāji ļauj izveidot savu apgalvojumu loģiku, padarot jūsu testus izteiksmīgākus un lasāmākus.

Pielāgotu salīdzinātāju izveide

Jūs varat paplašināt Jest expect objektu ar saviem salīdzinātājiem.

Piemērs: Derīga e-pasta formāta pārbaude

Jūsu Jest iestatīšanas failā (piem., jest.setup.js, kas konfigurēts jest.config.js):

// jest.setup.js

expect.extend({
  toBeValidEmail(received) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    const pass = emailRegex.test(received);

    if (pass) {
      return {
        message: () => `expected ${received} not to be a valid email`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be a valid email`,
        pass: false,
      };
    }
  },
});

// In your jest.config.js
// module.exports = { setupFilesAfterEnv: ['<rootDir>/jest.setup.js'] };

Jūsu testa failā:

// validation.test.js

test('should validate email formats', () => {
  expect('test@example.com').toBeValidEmail();
  expect('invalid-email').not.toBeValidEmail();
  expect('another.test@sub.domain.co.uk').toBeValidEmail();
});

Pielāgoto salīdzinātāju priekšrocības

Asinhrono operāciju testēšana

JavaScript ir ļoti asinhrona valoda. Jest nodrošina lielisku atbalstu solījumu (promises) un async/await testēšanai.

async/await izmantošana

Šis ir modernākais un vislasāmākais veids, kā testēt asinhrono kodu.

Piemērs: Asinhronas funkcijas testēšana

// dataService.js
export const fetchUserData = async (userId) => {
  // Imitēt datu ielādi pēc aizkaves
  await new Promise(resolve => setTimeout(resolve, 50));
  if (userId === 1) {
    return { id: 1, name: 'Alice' };
  } else {
    throw new Error('User not found');
  }
};

// dataService.test.js
import { fetchUserData } from './dataService';

test('fetches user data correctly', async () => {
  const user = await fetchUserData(1);
  expect(user).toEqual({ id: 1, name: 'Alice' });
});

test('throws error for non-existent user', async () => {
  await expect(fetchUserData(2)).rejects.toThrow('User not found');
});

.resolves un .rejects izmantošana

Šie salīdzinātāji vienkāršo solījumu izpildes un noraidīšanas testēšanu.

Piemērs: .resolves/.rejects izmantošana

// dataService.test.js (continued)

test('fetches user data with .resolves', () => {
  return expect(fetchUserData(1)).resolves.toEqual({ id: 1, name: 'Alice' });
});

test('throws error for non-existent user with .rejects', () => {
  return expect(fetchUserData(2)).rejects.toThrow('User not found');
});

Taimeru apstrāde

Funkcijām, kas izmanto setTimeout vai setInterval, Jest nodrošina taimera kontroli.

Piemērs: Taimeru kontrolēšana

// delayedGreeter.js
export const greetAfterDelay = (name, callback) => {
  setTimeout(() => {
    callback(`Hello, ${name}!`);
  }, 1000);
};

// delayedGreeter.test.js
import { greetAfterDelay } from './delayedGreeter';

jest.useFakeTimers(); // Iespējot viltus taimerus

test('greets after delay', () => {
  const mockCallback = jest.fn();
  greetAfterDelay('World', mockCallback);

  // Pārbīdīt taimerus uz priekšu par 1000 ms
  jest.advanceTimersByTime(1000);

  expect(mockCallback).toHaveBeenCalledTimes(1);
  expect(mockCallback).toHaveBeenCalledWith('Hello, World!');
});

// Atjaunot īstos taimerus, ja nepieciešams citur
jest.useRealTimers();

Testu organizācija un struktūra

Pieaugot jūsu testu kopumam, organizācija kļūst kritiski svarīga uzturamībai.

Describe un It bloki

Izmantojiet describe, lai grupētu saistītus testus, un it (vai test) atsevišķiem testa gadījumiem. Šī struktūra atspoguļo lietojumprogrammas modularitāti.

Piemērs: Strukturēti testi

describe('User Authentication Service', () => {
  let authService;

  beforeEach(() => {
    // Iestatīt imitācijas vai pakalpojumu instances pirms katra testa
    authService = require('./authService');
    jest.spyOn(authService, 'login').mockImplementation(() => Promise.resolve({ token: 'fake_token' }));
  });

  afterEach(() => {
    // Notīrīt imitācijas
    jest.restoreAllMocks();
  });

  describe('login functionality', () => {
    it('should successfully log in a user with valid credentials', async () => {
      const result = await authService.login('user@example.com', 'password123');
      expect(result.token).toBeDefined();
      // ... vairāk apgalvojumu ...
    });

    it('should fail login with invalid credentials', async () => {
      jest.spyOn(authService, 'login').mockRejectedValue(new Error('Invalid credentials'));
      await expect(authService.login('user@example.com', 'wrong_password')).rejects.toThrow('Invalid credentials');
    });
  });

  describe('logout functionality', () => {
    it('should clear user session', async () => {
      // Testēt izrakstīšanās loģiku...
    });
  });
});

Iestatīšanas un nojaukšanas "āķi" (Hooks)

Šie "āķi" ir būtiski, lai iestatītu imitētus datus, datu bāzes savienojumus vai notīrītu resursus starp testiem.

Testēšana globālai auditorijai

Izstrādājot lietojumprogrammas globālai auditorijai, testēšanas apsvērumi paplašinās:

Internacionalizācija (i18n) un lokalizācija (l10n)

Pārliecinieties, ka jūsu UI un ziņojumi pareizi pielāgojas dažādām valodām un reģionālajiem formātiem.

Piemērs: Lokalizēta datuma formatēšanas testēšana

// dateUtils.js
export const formatLocalizedDate = (date, locale) => {
  return new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'numeric', day: 'numeric' }).format(date);
};

// dateUtils.test.js
import { formatLocalizedDate } from './dateUtils';

test('formats date correctly for US locale', () => {
  const date = new Date(2023, 10, 15); // 2023. gada 15. novembris
  expect(formatLocalizedDate(date, 'en-US')).toBe('11/15/2023');
});

test('formats date correctly for German locale', () => {
  const date = new Date(2023, 10, 15);
  expect(formatLocalizedDate(date, 'de-DE')).toBe('15.11.2023');
});

Laika joslu apzināšanās

Testējiet, kā jūsu lietojumprogramma apstrādā dažādas laika joslas, īpaši tādām funkcijām kā plānošana vai reāllaika atjauninājumi. Sistēmas pulksteņa imitēšana vai bibliotēku, kas abstrahē laika joslas, izmantošana var būt noderīga.

Kultūras nianses datos

Apsveriet, kā skaitļi, valūtas un citi datu attēlojumi var tikt uztverti vai gaidīti atšķirīgi dažādās kultūrās. Šeit īpaši noderīgi var būt pielāgoti salīdzinātāji.

Uzlabotas tehnikas un stratēģijas

Uz testiem balstīta izstrāde (TDD) un uz uzvedību balstīta izstrāde (BDD)

Jest labi saskan ar TDD (Sarkans-Zaļš-Refaktorēt) un BDD (Dots-Kad-Tad) metodoloģijām. Rakstiet testus, kas apraksta vēlamo uzvedību, pirms rakstāt implementācijas kodu. Tas nodrošina, ka kods jau no paša sākuma tiek rakstīts, domājot par testējamību.

Integrācijas testēšana ar Jest

Lai gan Jest izceļas vienībtestos, to var izmantot arī integrācijas testiem. Var palīdzēt mazāka atkarību imitēšana vai tādu rīku kā Jest runInBand opcijas izmantošana.

Piemērs: API mijiedarbības testēšana (vienkāršots)

// apiService.js
import axios from 'axios';

const API_BASE_URL = 'https://api.example.com';

export const createProduct = async (productData) => {
  const response = await axios.post(`${API_BASE_URL}/products`, productData);
  return response.data;
};

// apiService.test.js (Integration test)
import axios from 'axios';
import { createProduct } from './apiService';

// Imitēt axios integrācijas testiem, lai kontrolētu tīkla slāni
jest.mock('axios');

test('creates a product via API', async () => {
  const mockProduct = { id: 1, name: 'Gadget' };
  const responseData = { success: true, product: mockProduct };

  axios.post.mockResolvedValue({
    data: responseData,
    status: 201,
    headers: { 'content-type': 'application/json' },
  });

  const newProductData = { name: 'Gadget', price: 99.99 };
  const result = await createProduct(newProductData);

  expect(axios.post).toHaveBeenCalledWith(`${process.env.API_BASE_URL || 'https://api.example.com'}/products`, newProductData);
  expect(result).toEqual(responseData);
});

Paralēlisms un konfigurācija

Jest var palaist testus paralēli, lai paātrinātu izpildi. Konfigurējiet to savā jest.config.js failā. Piemēram, iestatījums maxWorkers kontrolē paralēlo procesu skaitu.

Pārklājuma pārskati

Izmantojiet Jest iebūvēto pārklājuma ziņošanu, lai identificētu jūsu koda bāzes daļas, kas netiek testētas. Palaidiet testus ar --coverage, lai ģenerētu detalizētus pārskatus.

jest --coverage

Pārklājuma pārskatu pārskatīšana palīdz nodrošināt, ka jūsu uzlabotās testēšanas metodes efektīvi aptver kritisko loģiku, ieskaitot internacionalizācijas un lokalizācijas koda ceļus.

Noslēgums

Uzlabotu Jest testēšanas metožu apgūšana ir nozīmīgs solis ceļā uz uzticamas, viegli uzturamas un augstas kvalitātes programmatūras izveidi globālai auditorijai. Efektīvi izmantojot imitēšanu, momentuzņēmumu testēšanu, pielāgotus salīdzinātājus un asinhronās testēšanas tehnikas, jūs varat uzlabot sava testu komplekta robustumu un iegūt lielāku pārliecību par jūsu lietojumprogrammas uzvedību dažādos scenārijos un reģionos. Šo metožu pieņemšana dod iespēju izstrādes komandām visā pasaulē nodrošināt izcilu lietotāja pieredzi.

Sāciet iekļaut šīs uzlabotās tehnikas savā darba plūsmā jau šodien, lai paaugstinātu savas JavaScript testēšanas prakses līmeni.