Tổng hợp 85 câu hỏi phỏng vấn Testing kèm đáp án chi tiết, song ngữ Việt–Anh — sắp xếp từ cơ bản đến nâng cao. Ôn luyện miễn phí, tự động lưu tiến độ.
Jest là JavaScript testing framework từ Meta, phổ biến nhất trong hệ sinh thái JS — zero-config với Create React App và Next.js, hỗ trợ TypeScript qua ts-jest hoặc babel-jest. Tính năng chính: - Test isolation — mỗi test file chạy trong environment riêng (jsdom…
describe nhóm các test liên quan thành suite, it/test định nghĩa từng test case, expect tạo assertion với matchers. - describe — nhóm test, nest được nhiều cấp; tên test nên đọc như documentation: it('should return 404 when user not found'). - Matchers thường dùng…
jest.fn() tạo mock function độc lập, jest.mock() thay thế cả module, jest.spyOn() bọc method có sẵn và mặc định vẫn gọi implementation thật. - jest.fn() — track calls/arguments/return values; mockReturnValue(val) cho sync, mockResolvedValue/mockRejectedValue cho Promise, mockImplementation(fn) cho logic tuỳ biến. - jest.mock('path') — auto-mock toàn…
Vitest là test framework xây trên Vite với API tương thích Jest — reuse Vite config và transforms nên không cần cấu hình riêng cho test, nhanh hơn nhờ esbuild và native ESM. - Migrate dễ — từ Jest thường chỉ cần đổi import và…
Cypress là E2E testing framework chạy trong cùng event loop với app (không qua WebDriver protocol như Selenium) — điểm mạnh là time-travel debugging, auto-retry và cy.intercept(). - Kiến trúc — chạy trong browser cùng app nên truy cập được application state, intercept network request,…
Playwright (Microsoft) là lựa chọn hiện đại cho E2E testing — cross-browser thực sự (Chromium/Firefox/WebKit), async/await chuẩn, parallel execution built-in, Trace Viewer để debug lỗi trên CI. - Cross-browser + parallel — hỗ trợ cả WebKit (Safari); test file chạy song song mặc định, config…
TDD viết test trước code, theo chu trình Red-Green-Refactor. - Red — viết test cho behavior mong muốn; test fail vì code chưa tồn tại. - Green — viết lượng code tối thiểu để test pass — không over-engineer. - Refactor — cải thiện cấu…
BDD là extension của TDD, tập trung vào behavior từ góc nhìn user/business thay vì implementation kỹ thuật. - Given-When-Then — Given (ngữ cảnh/tiền điều kiện: 'Given a user with $100 in account'), When (hành động: 'When they transfer $50'), Then (kết quả mong đợi:…
- Unit test: kiểm tra một đơn vị nhỏ (hàm, class) tách riêng, mock/stub dependency. Chạy trong mili-giây, fail chỉ đúng chỗ hỏng → dễ tìm nguyên nhân, viết nhiều nhất. - Integration test: kiểm tra nhiều thành phần ghép với nhau — code với…
Snapshot testing serialize output (component render, JSON object, string) vào file .snap — lần chạy sau so sánh với snapshot đã lưu, fail nếu có thay đổi. - Update — khi thay đổi là có chủ đích: jest -u (--updateSnapshot) cập nhật tất cả; kết…
Code coverage đo phần trăm code mà test chạy qua — sinh bởi Istanbul (Jest) hoặc V8 (Vitest V8 provider). Các metric: - Statement coverage — % statement được chạy. - Branch coverage — % nhánh được cover: mỗi if/else/ternary/&&/ tạo 2 nhánh, phải test…
Unit test kiểm tra một function/class cô lập với mọi dependency được mock; integration test kiểm tra tương tác giữa nhiều thành phần với dependency thật hoặc mock tối thiểu. - Unit — nhanh (<1ms), ổn định, dễ xác định vị trí lỗi, không cần…
Bộ công cụ phổ biến nhất để test React components là Jest kết hợp React Testing Library (RTL), trong đó RTL theo triết lý test hành vi người dùng thay vì chi tiết implementation bên trong. Cách viết test cơ bản là dùng render() để…
AAA là cấu trúc chuẩn cho mỗi unit test, giúp test dễ đọc và maintain. Arrange (chuẩn bị): khởi tạo data, mocks, objects cần thiết — đây là phần dài nhất. Act (thực hiện): gọi function/method đang test — chỉ một dòng, test một behavior…
MSW intercept network request ở tầng service worker (browser) hoặc msw/node (Node.js), cho phép mock API response mà không thay đổi code của app. Khác với mock fetch trực tiếp (jest.spyOn(global, 'fetch')): MSW intercept ở network layer — app code không biết gì, không cần…
Flaky test là test khi pass khi fail dù code không đổi. Cái hại lớn nhất không phải bản thân lỗi, mà là team mất niềm tin vào test suite rồi bắt đầu bỏ qua cả những lần fail thật. Sáu nguyên nhân hay gặp:…
Coverage threshold làm CI fail khi độ phủ tụt dưới mức tối thiểu, khai báo trong jest.config.js: - collectCoverageFrom rất quan trọng: không có nó thì file hoàn toàn chưa có test sẽ không bị tính vào coverage (Jest chỉ đếm file được test import),…
@testing-library/react có ba nhóm query, khác nhau ở chỗ element không tồn tại thì chuyện gì xảy ra: - getBy — throw error ngay. Dùng khi element bắt buộc phải có; fail nhanh và thông báo rõ nhất. - queryBy — trả về null. Dùng…
Nên test theo nhóm: input rỗng hoặc nhỏ nhất; case bình thường; duplicate; giá trị âm/zero nếu đề cho phép; boundary như target ở đầu/cuối; case không có đáp án; case tất cả phần tử giống nhau; case lớn để kiểm complexity. Với string, test…
Dry-run là đọc code như máy tính: chọn một ví dụ nhỏ rồi lần theo từng dòng, ghi giá trị biến ra giấy hoặc comment. Tập trung vào những chỗ hay sai: điều kiện vòng lặp (< hay <=), cập nhật pointer/index, khởi tạo và…
Phần lớn bug interview rơi vào vài nhóm quen thuộc: (1) off-by-one — sai < vs <=, index n thay vì n-1, quên phần tử cuối; (2) null/empty — không xử lý mảng rỗng, list rỗng, hoặc node null; (3) quên cập nhật state —…
Kỹ thuật hữu ích là "phân vùng tương đương" — chia input thành các nhóm mà code xử lý khác nhau, rồi lấy đại diện mỗi nhóm cộng với các điểm biên giữa chúng. Ví dụ bài tìm số trong mảng sorted: nhóm "có trong…
Cả hai đều kiểm chứng chất lượng nhưng trả lời hai câu hỏi khác nhau: - Verification — "Có làm đúng cách không?" Kiểm tra sản phẩm/tài liệu có bám đúng đặc tả, thiết kế, chuẩn hay không. Thường là static (review, inspection, phân tích…
Đây là một chuỗi nhân quả, không phải từ đồng nghĩa: - Error (sai sót) — hành động sai của con người, ví dụ lập trình viên hiểu nhầm yêu cầu hoặc gõ nhầm. - Defect / Fault / Bug (khiếm khuyết) — chỗ sai…
Khác nhau ở mức độ biết về cấu trúc bên trong khi thiết kế test: - Black-box — dựa trên đặc tả/hành vi, không cần biết code chạy ra sao. Kỹ thuật: equivalence partitioning, boundary value analysis, decision table. Trả lời "đầu vào này thì…
- Functional testing — kiểm tra hệ thống làm gì: các chức năng có chạy đúng theo yêu cầu không (đăng nhập, tính tiền, tìm kiếm...). Tập trung vào hành vi và kết quả. - Non-functional testing — kiểm tra hệ thống làm tốt tới…
- Severity (mức nghiêm trọng) — lỗi ảnh hưởng tới hệ thống nặng tới đâu về mặt kỹ thuật. Do tester đánh giá (crash, mất dữ liệu → cao; lệch giao diện nhỏ → thấp). - Priority (mức ưu tiên) — lỗi cần được sửa…
Luồng chuẩn từ lúc phát hiện tới lúc đóng: 1. New — tester vừa log lỗi. 2. Assigned — lead/PM giao cho một dev. 3. Open / In Progress — dev tiếp nhận và đang sửa. 4. Fixed — dev báo đã sửa xong. 5.…
Hai kỹ thuật black-box để giảm số test case mà vẫn phủ tốt: - Equivalence Partitioning (EP) — chia miền đầu vào thành các lớp tương đương, sao cho trong mỗi lớp mọi giá trị được xử lý như nhau. Chỉ cần test một đại…
Cả hai đều là kiểm nhanh trước khi test sâu, nhưng khác về phạm vi và độ sâu: - Smoke testing — rộng và nông. Chạy nhanh qua các chức năng cốt lõi để xác nhận build đủ ổn định để test tiếp (app mở…
- Static testing — kiểm tra sản phẩm không chạy code. Gồm review, walkthrough, inspection (tài liệu, yêu cầu, thiết kế, code) và static analysis (linter, phân tích tĩnh). Ưu điểm: bắt lỗi sớm và rẻ, ngay từ khâu yêu cầu — trước khi lỗi…
Bốn mức đi từ nhỏ tới lớn, mỗi mức có mục tiêu và người thực hiện riêng: 1. Unit / Component — test từng module/hàm riêng lẻ, thường do dev viết. Nhanh, cô lập, bắt lỗi logic sớm nhất. 2. Integration — test sự tương…
- Re-testing (confirmation testing) — chạy lại đúng test case đã fail trên build đã sửa, để xác nhận defect thực sự hết. Phạm vi hẹp, bám đúng vào chỗ vừa fix. - Regression testing — chạy lại các test case của phần vốn đang…
STLC là chuỗi hoạt động test có cấu trúc, thường gồm sáu pha: 1. Requirement analysis — phân tích yêu cầu, xác định cái gì testable, làm rõ tiêu chí. 2. Test planning — lập kế hoạch: phạm vi, chiến lược, nguồn lực, lịch, tiêu…
Khác nhau ở mức độ chi tiết: - Test scenario — mô tả cấp cao "cần test cái gì": một chức năng hoặc luồng cần kiểm chứng, ví dụ "Kiểm tra chức năng đăng nhập". Trả lời what. - Test case — các bước chi…
Điểm mấu chốt: Jest phải biết khi nào async operation kết thúc — nếu không, test hoàn thành trước khi assertion chạy và pass giả. - async/await hoặc return promise — cách chuẩn: test('fetch', async () = { const data = await fetchData(); expect(data).toBe('ok') }),…
Không viết test cho toàn bộ codebase. Bắt đầu ở nơi lỗi gây thiệt hại lớn nhất và code dễ test nhất. Thứ tự thực tế: 1. Dựng hạ tầng test trước — cài runner (Vitest/Jest), 1 lệnh pnpm test chạy được, gắn vào CI.…
Ưu tiên logic nghiệp vụ trước, UI sau. Lý do: logic nghiệp vụ (tính tiền, áp mã giảm giá, kiểm tra quyền, chuyển trạng thái đơn) là chỗ sai thì hậu quả không thể hoàn tác được, lại thường là pure function — viết test…
Viết test trước — và phải thấy nó đỏ trước khi sửa code. Quy trình thực tế: 1. Tái hiện bug bằng một test nhỏ nhất có thể, dùng đúng dữ liệu gây lỗi (đơn hàng id X, chuỗi đầu vào Y). 2. Chạy test…
Không có định nghĩa duy nhất, và đó là lý do câu này hay được hỏi để xem bạn hiểu mục đích hay chỉ thuộc nhãn. Cách phân biệt dùng được trong thực tế, dựa trên thứ test kiểm soát được: - Unit test: chỉ…
Vì test đã mock đúng cái phần có bug. Mock thay thành phần thật bằng thứ bạn tự định nghĩa — nên nó chỉ kiểm chứng được rằng code gọi đúng thứ bạn tưởng tượng, không kiểm chứng thứ đó có tồn tại và hoạt…
Nguyên tắc: không để test phụ thuộc đồng hồ thật. Có hai cách, ưu tiên cách một. 1. Truyền thời gian vào như một dependency. Hàm nhận now (hoặc một clock) thay vì tự gọi Date.now(). Test truyền mốc thời gian cố định, không cần…
Mọi nguồn non-deterministic phải được đẩy ra biên rồi thay bằng giá trị cố định trong test. Ngẫu nhiên và UUID: đừng gọi trực tiếp trong hàm nghiệp vụ; nhận qua tham số hoặc mock module sinh id. Network: chặn ở tầng HTTP thay vì…
Factory hơn fixture cứng trong hầu hết trường hợp. Fixture kiểu một file JSON dùng chung cho cả trăm test sẽ dần bị "ai cũng thêm một trường" và không test nào dám sửa vì sợ hỏng test khác. Factory là hàm tạo bản ghi…
Đo trước, tối ưu sau. Cả Jest lẫn Vitest đều in được thời gian từng file (--reporter=verbose, Jest có --detectOpenHandles để tìm handle treo). Thường 10% số test chiếm phần lớn thời gian. Các hướng cắt, theo thứ tự hiệu quả: 1. Bỏ chờ thật.…
Testing Library xếp query theo thứ tự càng gần cách người dùng tìm phần tử càng tốt: 1. Accessible queries — getByRole, getByLabelText, getByPlaceholderText, getByText, getByDisplayValue. 2. Semantic queries — getByAltText, getByTitle. 3. Test ID — getByTestId, dùng khi không còn cách nào khác. getByRole…
Bốn nguyên nhân chiếm phần lớn trường hợp: 1. Text bị chia nhỏ qua nhiều element. getByText mặc định so khớp trên từng node text riêng lẻ, không phải chuỗi ghép lại của cả cây DOM. Cần khớp cả cụm thì dùng hàm matcher hoặc…
fireEvent.click(el) bắn đúng một DOM event vào element. userEvent.click(el) mô phỏng cả chuỗi tương tác mà trình duyệt sinh ra khi người dùng thật click: pointerdown, mousedown, focus, pointerup, mouseup, click. Khác biệt thấy rõ trong thực tế: - fireEvent.change(input, { target: { value: "abc"…
Test theo đúng thao tác người dùng: điền sai → submit → assert thông báo lỗi hiển thị và callback submit không được gọi. Không đụng vào state nội bộ hay method của thư viện form. Lưu ý: - findBy cho lỗi đầu tiên vì…
Chặn ở tầng network (MSW hoặc mock fetch), rồi assert theo những gì người dùng thấy ở từng giai đoạn. Quy tắc chọn query trong luồng async: - getBy cho thứ có ngay lập tức (skeleton, tiêu đề tĩnh). - findBy cho thứ xuất hiện…
MSW chặn request ở tầng network (Service Worker trên browser, interceptor trên Node), nên code ứng dụng không biết mình đang bị mock — không cần sửa fetch hay axios instance. Setup dùng chung cho cả suite: onUnhandledRequest: "error" rất đáng bật: request nào chưa…
waitFor chạy lại callback theo chu kỳ (mặc định 50ms) cho tới khi không ném lỗi, hoặc hết timeout (mặc định 1000ms). Ba lỗi hay gặp: 1. Nhồi nhiều assertion vào một waitFor. Assertion đầu fail thì các assertion sau không chạy; khi test fail…
Dùng renderHook của React Testing Library — nó render một component rỗng chỉ để gọi hook, trả về result.current là giá trị hook trả ra. Ba điểm hay sai: - result.current là snapshot. Không destructure ra biến (const { count } = result.current) rồi assert…
Tạo một custom render bọc sẵn mọi provider rồi re-export thay cho render của RTL. Ba chi tiết quyết định test có ổn định hay không: - retry: false cho React Query. Mặc định client retry 3 lần với backoff, nên test case lỗi sẽ…
vi.mock (và jest.mock) được hoist lên đầu file, chạy trước mọi import và mọi khai báo biến. Đó là điều kiện bắt buộc để module thật không kịp được nạp. Hai cách sửa: Với Jest, quy ước là đặt tên biến bắt đầu bằng mock…
Không dùng setTimeout thật để chờ — dùng fake timer và tự tua đồng hồ. Vì sao hay treo: user-event v14 tự chèn delay giữa các phím bằng setTimeout. Khi fake timer đang bật mà không ai đẩy đồng hồ, timer đó không bao giờ…
Mặc định nên chọn HTTP in-process: khởi tạo app trong bộ nhớ rồi bắn request qua thư viện của framework (supertest với Express/Nest, WebApplicationFactory với ASP.NET, MockMvc với Spring). Không mở cổng, không cần server chạy nền, nhưng vẫn đi qua routing, middleware, validation, serialize…
Một report dùng được phải trả lời đủ bốn câu: làm gì, mong đợi gì, thực tế ra sao, ở đâu. - Tiêu đề: một dòng nêu triệu chứng + ngữ cảnh. "Đặt hàng lỗi" thì vô dụng; "Checkout trả 500 khi mã giảm giá…
QA vào cuộc từ lúc refine ticket, không phải khi dev báo "code xong". Ở buổi refine, QA là người hỏi các câu làm lộ yêu cầu thiếu: dữ liệu rỗng thì hiển thị gì, user không có quyền thì thấy gì, gọi lại lần…
Bug loại này gần như luôn đến từ chênh lệch môi trường chứ không phải code. Các nguồn hay gặp, xếp theo tần suất: - Dữ liệu: staging vài trăm bản ghi, production vài triệu. Query thiếu index chạy 20ms ở staging và 8 giây…
Chọn Testcontainers: mỗi lần chạy test, thư viện khởi động một container Postgres/MySQL/Redis thật qua Docker, cấp cổng ngẫu nhiên, chạy migration rồi dọn container khi xong. Vì sao không chọn hai phương án kia: - SQLite in-memory nhanh nhưng khác dialect: không có jsonb,…
Ba cách, đánh đổi khác nhau: 1. Transaction rollback mỗi test — mở transaction trước test, ROLLBACK sau test. Nhanh nhất, không cần dọn tay. Giới hạn: code đang được test phải dùng đúng connection đó, nên hỏng ngay khi app tự mở transaction riêng,…
Không copy nguyên bản. Dữ liệu production chứa thông tin cá nhân (email, số điện thoại, địa chỉ, lịch sử thanh toán); đưa nó xuống môi trường có quyền truy cập rộng hơn là rủi ro lộ dữ liệu và vi phạm cam kết với…
Ba mức, dùng cả ba ở các tầng khác nhau chứ không chọn một: 1. Test double ở tầng service (đa số case). Đưa client bên thứ ba ra sau một interface của mình, test truyền bản giả vào. Ở đây kiểm những thứ thuộc…
Tách làm hai tầng. Tầng chỉ có logic (phần lớn test): hàm xử lý nhận vào một message đã parse và trả về kết quả, không tự kết nối broker. Test ở đây nhanh và bao được các case quan trọng: - Message hợp lệ…
Trước khi chạy phải có tiêu chí đạt bằng số, nếu không thì kết quả chỉ là một đống biểu đồ. Tiêu chí gồm ba phần: mức tải (bao nhiêu người dùng đồng thời hoặc bao nhiêu request/giây), ngưỡng độ trễ, ngưỡng tỉ lệ lỗi.…
Chọn theo rủi ro, không chọn theo cảm tính hay theo thứ tự bảng test case. Thứ tự ưu tiên: 1. Luồng sinh tiền và luồng hỏng là chặn người dùng: đăng nhập, thanh toán, đặt hàng, gửi thông báo giao dịch. Hỏng ở đây…