![]()
Hãy tưởng tượng bạn vừa hoàn thành một tính năng Giỏ hàng cực kỳ phức tạp. Bạn tự tay vuốt, chạm, thêm bớt sản phẩm trên điện thoại và thấy mọi thứ chạy hoàn hảo. Bạn tự tin đẩy code lên cho sếp.
Nhưng sáng hôm sau, hàng loạt báo cáo lỗi gửi về: "Tính năng Thanh toán bị hỏng!". Hóa ra, đoạn code bạn vừa thêm vào Giỏ hàng đã vô tình làm "chết" màn hình Thanh toán mà bạn không hề hay biết.
Đây là một vòng lặp ác mộng của lập trình viên: Sửa 1 bug, sinh ra 3 bug mới.
Để chấm dứt cảnh phải tự tay bấm test lại toàn bộ ứng dụng mỗi khi thay đổi một dòng code, các công ty lớn áp dụng Kiểm thử tự động (Automated Testing). Và trong bài học này, chúng ta sẽ làm quen với lớp phòng thủ đầu tiên và quan trọng nhất: Unit Test (Kiểm thử mức đơn vị).
1. Unit Test là gì?
Trong kim tự tháp kiểm thử phần mềm, Unit Test nằm ở dưới cùng. Nó là việc bạn viết ra những đoạn code ngắn... để kiểm tra xem những đoạn code chính của bạn có hoạt động đúng như kỳ vọng hay không.

Thay vì kiểm tra toàn bộ ứng dụng cùng lúc, Unit Test cô lập từng "đơn vị" nhỏ nhất (một hàm tính toán, một thẻ <Button>, một màn hình nhỏ) và kiểm tra độc lập.
- Ví dụ: Bạn có một hàm
calculateDiscount(price, discount). Bạn sẽ viết một Unit Test để kiểm tra xem nếu truyền vào100và20%, nó có trả về đúng số80hay không.
2. Cặp bài trùng: Jest & React Native Testing Library
Trong hệ sinh thái React Native, có hai công cụ thống trị mảng Unit Test mà bạn bắt buộc phải biết:

- Jest: Đây là một công cụ chạy test (Test Runner) do Facebook phát triển. Nó cung cấp môi trường để chạy code, các hàm kiểm tra kết quả, như
expect(a).toBe(b), và báo cáo xem test nào Pass hoặc Fail. - React Native Testing Library: Jest chỉ hiểu JavaScript thuần. Để test được các giao diện (như
<View>,<Text>), chúng ta cần RNTL. Thư viện này giúp "vẽ" các component của bạn ra một màn hình ảo trong bộ nhớ máy tính để kiểm tra xem chữ có hiện lên không, nút bấm có hoạt động không.
3. Cài đặt môi trường kiểm thử
Để bắt đầu, hãy mở Terminal ở thư mục dự án Expo của bạn và cài đặt các gói cần thiết:
npm install --save-dev jest @types/jest @testing-library/react-native react-test-renderer
(Lưu ý: Chúng ta dùng cờ --save-dev vì các thư viện test này chỉ dùng trong lúc lập trình, không được đóng gói vào app thực tế để tránh làm nặng app).
Tiếp theo, mở file package.json, tìm mục "scripts" và thêm dòng lệnh test vào:
"scripts": {
"start": "expo start",
"test": "jest"
}
4. Kiểm tra logic hàm: Jest
Hãy bắt đầu với thứ dễ nhất: Kiểm tra một hàm JavaScript thuần túy.
Bước 1: Tạo file logic
Tạo file src/utils/math.js:
export const add = (a, b) => {
return a + b
}
Bước 2: Viết bài Test
Tạo file src/utils/math.test.js. (Jest sẽ tự động tìm tất cả các file có chữ .test.js để chạy).
import { add } from './math'
// Khai báo một nhóm các bài test
describe('Kiểm thử file math.js', () => {
// Khai báo một bài test cụ thể (it hoặc test)
it('Hàm add phải cộng đúng 2 số', () => {
// 1. Chuẩn bị dữ liệu
const ketQua = add(2, 3)
// 2. Kỳ vọng (Expect)
expect(ketQua).toBe(5) // Tôi kỳ vọng kết quả phải là 5
})
it('Hàm add xử lý được số âm', () => {
expect(add(-2, 5)).toBe(3)
})
})
Bước 3: Chạy test
Mở Terminal và gõ npm run test. Nếu màn hình hiện ra chữ PASS màu xanh lá cây, chúc mừng bạn đã viết thành công bài test đầu tiên!

5. Kiểm thử Giao diện: React Native Testing Library
Test hàm toán học thì dễ rồi, vậy làm sao để test một nút bấm trên màn hình điện thoại? Đây là lúc RNTL trổ tài.
Giả sử bạn có một component Nút bấm kèm theo bộ đếm số lần bấm:
// src/components/Counter.tsx
import React, { useState } from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<View>
<Text testID="count-display">Số lần bấm: {count}</Text>
<TouchableOpacity testID="increment-btn" onPress={() => setCount(count + 1)}>
<Text>Tăng</Text>
</TouchableOpacity>
</View>
)
}
(Mẹo nhỏ: Thuộc tính testID giống như gắn một cái bảng tên ẩn cho các thẻ View/Text, giúp RNTL dễ dàng tìm thấy chúng trong lúc test).
Bây giờ, hãy viết test cho component này ở file Counter.test.tsx:
import React from 'react'
import { render, screen, fireEvent } from '@testing-library/react-native'
import Counter from './Counter'
describe('Kiểm thử component Counter', () => {
it('Nên hiển thị số 0 lúc ban đầu', () => {
// 1. Render (vẽ) component lên màn hình ảo
render(<Counter />)
// 2. Tìm thẻ text thông qua testID
const textElement = screen.getByTestId('count-display')
// 3. Kiểm tra xem nội dung bên trong có chứa số 0 không
expect(textElement.props.children.join('')).toContain('Số lần bấm: 0')
})
it('Nên tăng lên 1 khi nhấn nút Tăng', () => {
render(<Counter />)
// 1. Tìm nút bấm và thẻ hiển thị số
const button = screen.getByTestId('increment-btn')
const textElement = screen.getByTestId('count-display')
// 2. Giả lập hành động người dùng bấm vào nút (fireEvent)
fireEvent.press(button)
// 3. Kiểm tra lại nội dung, lúc này kỳ vọng phải là 1
expect(textElement.props.children.join('')).toContain('Số lần bấm: 1')
})
})
Quá tuyệt vời! Bạn vừa giả lập được việc một người dùng bấm vào màn hình điện thoại và hệ thống tự động kiểm tra xem số có nhảy đúng hay không.
6. Lời khuyên thực chiến khi viết Unit Test
Để tránh sa đà vào việc viết test một cách vô tội vạ, hãy ghi nhớ những nguyên tắc sau:
- Không test những thứ thuộc về Framework: Bạn không cần phải test xem hàm
useStatecủa React hay<View>của React Native có chạy đúng không. Đó là việc của Facebook. Hãy test logic của bạn. - Tập trung vào Logic phức tạp: Ưu tiên test các hàm xử lý tiền tệ, tính điểm, định dạng ngày tháng, hoặc các điều kiện
if/elsechằng chịt. - Test hành vi người dùng: Với RNTL, hãy test như một người dùng thật (tìm nút, bấm, xem kết quả trên màn hình), đừng cố gắng truy cập vào các biến State ngầm bên trong component.
Kết luận: Unit Test là tấm khiên vững chắc
Unit Test giống như việc bạn xây móng nhà. Ban đầu bạn sẽ cảm thấy viết test tốn gấp đôi thời gian so với chỉ viết code. Nhưng khi ứng dụng của bạn lớn lên, có hàng chục tính năng đan xen, Unit Test chính là tấm khiên vững chắc nhất bảo vệ bạn khỏi những đêm thức trắng sửa bug!
Cùng với việc đảm bảo code đã chạy mượt và không có lỗi, chúng ta đã sẵn sàng bước vào khâu cuối cùng của mọi dự án lập trình Mobile.
Hãy sẵn sàng nhé, ở bài tiếp theo, chúng ta sẽ tự tay tạo ra file APK/AAB cho Android và cấu hình chứng chỉ để tạo file IPA cho iOS!