Các loại Tests thiết yếu cho Front-End : Unit Tests, Performance Tests, Visual Regression Tests

🏛️ Vai trò kiểm soát chất lượng của Frontend Architect

  • Trong vai trò kiến trúc sư frontend, nhiệm vụ lớn nhất là giám sát sự phát triển của website và hệ thống thiết kế (design system).
  • Tuy nhiên, với quy mô lớn:
    • Đội ngũ có thể hàng chục người.
    • Hàng trăm commit mỗi tuần.
    • Hàng ngàn dòng code.
  • Không thể kỳ vọng một cá nhân có thể kiểm tra từng dòng code.
  • Nhưng mức độ giám sát đó lại cần thiết để đảm bảo hệ thống ổn định.

🐛 Các loại lỗi (regressions) có thể xảy ra khi có code mới

  1. Lỗi tính toán logic
    → Ví dụ: Sai giá sản phẩm.
  2. Lỗi chức năng quan trọng
    → Ví dụ: Người dùng không thể thanh toán bằng giỏ hàng.
  3. Lỗi giao diện người dùng (UI)
    → Ví dụ: Người dùng vẫn hoàn thành nhiệm vụ, nhưng giao diện gây khó chịu hoặc không đồng nhất.
  4. Lỗi hiệu năng
    → Ví dụ: Website chậm đến mức gần như không thể hoàn tất thanh toán từ một số thiết bị hoặc khu vực địa lý.

🔔 Hậu quả chung:
Tất cả các lỗi trên đều dẫn đến mất doanh thu.


🧪 Giải pháp chung cho các loại lỗi: Testing!

  • Kiến trúc sư không thể kiểm soát từng commit.
  • Thay vào đó, cần xây dựng hệ thống kiểm thử (testing suites) để đảm bảo chất lượng tự động.

📝 Nguyên tắc lập kế hoạch test coverage

🌟 1. Viết test khi hoặc trước khi viết code.

  • Test không chỉ viết sau mà có thể có trước (test-driven development).

🌟 2. Test là một phần sống của codebase.

  • Test phải được commit cùng hoặc sát bên repo của hệ thống.

🌟 3. Mọi test phải pass trước khi merge vào nhánh master.

  • Không có ngoại lệ: Tất cả các bài test phải chạy thành công trước khi code được hợp nhất.

🌟 4. Nhánh master luôn luôn ở trạng thái ổn định.

  • Bất kỳ commit nào làm hỏng:
    • Logic tính toán,
    • Chức năng kinh doanh cốt lõi,
    • Hiển thị UI chính xác,
    • Hoặc hiệu năng tổng thể → Đều không được phép merge.

🎯 Trọng tâm của Kiến trúc sư

  • Không dành thời gian đọc từng dòng code.
  • tập trung vào xây dựng hệ thống kiểm thử toàn diện và chất lượng để tự động hóa việc kiểm soát chất lượng.

🧩 Định nghĩa Unit Testing

  • Unit testing là quá trình:
    • Phân rã ứng dụng thành các chức năng nhỏ nhất.
    • Viết các bài kiểm thử tự động, có thể lặp lại, và luôn cho kết quả nhất quán.
  • Các bài unit test là nền tảng xây dựng tương lai của codebase.
  • ❗ Nếu không có unit tests:
    • Một chức năng ít dùng có thể hỏng hàng tháng trời mà không ai phát hiện.
  • ✅ Với unit tests:
    • Mọi chức năng hệ thống được kiểm tra trước khi code merge vào master (chứ chưa nói tới production).

🧰 Vai trò của Frontend Architect

  • Trang bị công cụ giúp developer làm việc hiệu quả hơn.
  • Unit testing là một công cụ thiết yếu.
  • Dù backend hay frontend, luôn có công cụ testing phù hợp:
    • PHPUnit (PHP)
    • NodeUnit (Node.js)
    • QUnit (JavaScript)
  • Không cần giỏi hết tất cả các framework ➔ Nhưng cần nắm vững các nguyên lý cơ bản để:
    • Viết code dễ test.
    • Nhanh chóng thích nghi với framework mới.

🛠️ Nguyên lý cơ bản: “Do one thing, and do it well”

🌟 Ví dụ hàm ban đầu:
Tính phí vận chuyển từ địa chỉ khách hàng đến trung tâm phân phối gần nhất.

🌟 Các bước hàm thực hiện:

  1. Tìm trung tâm phân phối gần nhất.
  2. Tính khoảng cách giữa hai địa chỉ.
  3. Tính phí vận chuyển dựa trên khoảng cách.

➡️ Nhận xét:
Một hàm nhưng làm 3 việc khác nhau ➔ Vi phạm nguyên tắc “làm một việc duy nhất và làm thật tốt”.


🔄 Refactor thành các đơn vị nhỏ

  • Tách ra 3 hàm riêng:
    1. lookupNearestCenter(address)
    2. calculateDistance(address1, address2)
    3. calculateShippingCost(distance)
  • Lợi ích:
    • Tái sử dụng được ở nhiều nơi.
    • Viết test đơn giản hơn rất nhiều.
    • Giảm số lượng chức năng phức tạp trong ứng dụng.

🧪 Test-Driven Development (TDD)

🌟 Trình tự:

  1. Viết test trước (cho những chức năng chưa tồn tại).
  2. Các test sẽ fail ban đầu ➔ Đây là mục tiêu đúng.
  3. Viết code để làm cho các test pass.

🌟 Áp dụng vào ví dụ vận chuyển:

  • Viết 3 test cho 3 hàm nhỏ trước.
  • Code các hàm cho đến khi tất cả test pass.

🌟 Ưu điểm:

  • test coverage hoàn chỉnh ngay từ đầu.
  • Hạn chế bug tiềm ẩn.

📜 Ví dụ test đơn giản với QUnit

🌟 Hàm tính phí vận chuyển:

function calculateShipping(distance) {
  let shipping;
  if (distance < 25) {
    shipping = 4;
  } else if (distance < 100) {
    shipping = 5;
  } else if (distance < 1000) {
    shipping = 6;
  } else {
    shipping = 7;
  }
  return shipping;
}

🌟 Test bằng QUnit:

QUnit.test('Calculate Shipping', function(assert) {
  assert.equal(calculateShipping(24), 4, "24 Miles");
  assert.equal(calculateShipping(99), 5, "99 Miles");
  assert.equal(calculateShipping(999), 6, "999 Miles");
  assert.equal(calculateShipping(1000), 7, "1000 Miles");
});

🧠 Giải thích:

  • assert.equal(actual, expected, message) so sánh giá trị thực tế và kỳ vọng.
  • Nếu khớp ➔ test pass.
  • Nếu ai đó sửa nhầm hàm calculateShipping, test sẽ fail ngay.

🔎 Các điểm mạnh khác của QUnit

  • Hỗ trợ test cả:
    • Hàm đồng bộ.
    • Hàm bất đồng bộ (asynchronous).
  • Có thể test các tương tác giao diện như click chuột, gõ phím.

📈 Bao nhiêu test coverage là đủ?

  • Không có quy tắc cứng nhắc.
  • Nếu test quá nhiều ➔ Dễ làm chậm quá trình phát triển.
  • Nếu test quá ít ➔ Dễ bị lỗi lọt vào production.

🌟 Gợi ý:

  • Bắt đầu từ những phần đơn giản nhất.
  • Sau đó mở rộng dần ra các phần phức tạphay lỗi trong quá khứ.

🛠️ Bắt đầu với project mới

🌟 Quy tắc tại Red Hat:

  • Mỗi user story đều phải:
    • Có kế hoạch dành thời gian cho viết test.
    • Ví dụ: nếu coding mất 8 giờ ➔ Thêm 2 giờ dành cho viết và kiểm tra test coverage.

🌟 Lưu ý:

  • Frontend Architect phải:
    • Bảo vệ quyền được viết test của developer.
    • Thuyết phục khách hàng hoặc quản lý về lợi ích lâu dài của testing.

Performance Testing


🎯 Mục tiêu của Performance Testing

  • Bảo vệ người dùng khỏi trải nghiệm tồi tệ do website kém hiệu suất.
  • Performance testing:
    • Không tìm lỗi hệ thống hoặc lỗi giao diện.
    • Nhưng cực kỳ quan trọng vì hiệu suất thấp cũng gây mất người dùng.

🌟 Các chỉ số đo hiệu suất website:

  • Page weight (trọng lượng trang).
  • Number of requests (số lượng request).
  • Time to First Byte (TTFB).
  • Load time (thời gian tải).
  • Scrolling performance (hiệu suất cuộn trang).

🏗️ Nguyên tắc cốt lõi: Thiết lập Performance Budget

  • Performance Budget = Đặt mục tiêu rõ ràng cho các chỉ số hiệu suất ➔ Kiểm tra trước mỗi lần merge hoặc deploy.
  • Nếu test fail ➔ Cần:
    • Điều chỉnh feature mới, hoặc
    • Loại bỏ những thứ nặng nề khác.

🌟 Lưu ý tâm lý:

  • Giống như quản lý tài chính: “ít hơn” không hấp dẫn.
  • Nhưng chi tiêu theo ngân sách ➔ Không nợ nần, không hối tiếc ➔ Website nhanh + người dùng hài lòng.

📊 Các cách thiết lập Performance Budget

🥇 1. Competitive Baseline

  • So sánh với đối thủ:
    • Đo thời gian tải, page weight,… của các trang chính.
    • Mục tiêu: Nhanh hơn ít nhất 20%.
      • Ví dụ: Đối thủ load trang sản phẩm 3s ➔ Trang bạn phải ≤ 2.4s.
  • Theo dõi định kỳ, vì đối thủ cũng không ngừng tối ưu.

🥈 2. Averaged Baseline

  • So với mặt bằng chung ngành.
  • Ví dụ số liệu từ HTTPArchive (tháng 4/2015):
    • Page weight trung bình: 2,061 KB.
    • Total requests trung bình: 99.
  • Mục tiêu cá nhân (giảm 20%):
    • Page weight: 1,648 KB.
    • Total requests: 79.

📐 Các chỉ số cần theo dõi

🔥 Raw Metrics

🌟 Page Weight

  • Website ngày càng nặng hơn:
    • 2011: 769 KB ➔ 2015: 2,061 KB (tăng 168%).
  • Vì sao cần giảm page weight:
    • Tăng tốc độ tải.
    • Tiết kiệm chi phí dữ liệu cho người dùng, đặc biệt ở các nước đang phát triển.
  • Giải pháp:
    • Tối ưu hình ảnh (nén PNG, giảm chất lượng JPEG, dùng <picture> + srcset).
    • Hạn chế số lượng và kiểu chữ custom fonts.
    • Dùng SVG inline thay vì icon fonts nặng.
    • Hạn chế dùng JS frameworks, jQuery plugins nếu không cần thiết.
    • Dùng minify và gzip để giảm kích thước file CSS/JS.

🌟 Number of HTTP Requests

  • Vấn đề:
    • Browser giới hạn số lượng request song song.
    • Nhiều file nhỏ ➔ nhiều round trips ➔ tải chậm.
  • Giải pháp:
    • Combine CSS/JS vào file lớn hơn.
    • Combine ảnh vào image sprite.
    • Lazy-load assets không cần thiết ngay từ đầu.
    • Dùng CDN để chia server ➔ Tăng số lượng request cùng lúc.

🕰️ Timing Metrics

⏳ Time to First Byte (TTFB)

  • Thời gian từ lúc gửi request đến khi nhận được byte đầu tiên.
  • Không phải chỉ số hiệu suất tổng thể, nhưng nên theo dõi.

🖌️ Time to Start Render

  • Thời gian bắt đầu vẽ giao diện cho người dùng.
  • Giải pháp:
    • Deferred JS/CSS.
    • Inline critical CSS.
    • Lazy load ảnh dưới viewport.

🏁 Time to Document Complete

  • Khi tất cả tài nguyên ban đầu được tải xong.
  • Không tính những file lazy-loaded sau.

🧮 Hybrid Metrics

🌟 PageSpeed Score

  • Công cụ Google PageSpeed:
    • Chấm điểm /100.
    • Gợi ý tối ưu: chặn render-blocking JS/CSS, tối ưu hình ảnh, cache, v.v.

🌟 Speed Index

  • Đo trung bình thời gian các phần visible của trang được hiển thị.
  • chỉ số mô phỏng sát nhất với trải nghiệm thực tế người dùng.

🛠️ Các công cụ tự động hóa Performance Testing

🚀 Grunt PageSpeed

  • Plugin Grunt để chạy Google PageSpeed tự động trước mỗi merge/build.

🌟 Cài đặt:

npm install grunt-pagespeed --save-dev

🌟 Gruntfile.js:

grunt.loadNpmTasks('grunt-pagespeed');

pagespeed: {
  options: {
    nokey: true,
    url: "http://redhat.com"
  },
  desktop: {
    options: {
      strategy: "desktop",
      threshold: 80
    }
  },
  mobile: {
    options: {
      strategy: "mobile",
      threshold: 80
    }
  }
}

🚀 Grunt Perfbudget

  • Plugin Grunt sử dụng WebPageTest API.
  • Test mô phỏng các kết nối và địa điểm khác nhau.

🌟 Cài đặt:

npm install grunt-perfbudget --save-dev

🌟 Gruntfile.js:

grunt.loadNpmTasks('grunt-perfbudget');

perfbudget: {
  default: {
    options: {
      url: 'http://www.redhat.com/en',
      key: 'YOUR_WEBPAGETEST_API_KEY',
      budget: {
        visualComplete: '4000', // ms
        SpeedIndex: '1500'       // ms
      }
    }
  }
}

🏆 Kết luận

  • Performance Testing + Performance Budget:
    • Bảo vệ website khỏi việc tụt hiệu suất ngầm.
    • Giúp phát triển feature mới mà không hy sinh trải nghiệm người dùng.

Visual Regression Testing


🎯 Vấn đề thực tế: Vòng lặp lỗi giao diện

  • Bạn làm việc rất cẩn thận để hoàn thiện form liên hệ theo đúng thiết kế Photoshop.
  • Code đã được ký duyệt, merge an toàn, và bạn chuyển sang task khác.
  • Nhưng vài tuần sau, bất ngờ:
    • Một ticket mới xuất hiện: “Form có lỗi!”
    • Một QA hoặc Designer nào đó so sánh với phiên bản PSD mới và phát hiện khác biệt.

🔔 Lý do có thể:

  • Ai đó vô tình sửa class chung mà bạn dùng cho form.
  • Thiết kế PSD không đồng bộ (file này khác file kia).
  • Decision Maker thay đổi yêu cầu mà không ghi nhận đó là thay đổi, lại ghi là bug.

🕵️ Các nguyên nhân phổ biến

👩‍💻 Unknowing Developers

  • Người khác vô tình sửa class dùng chung, ảnh hưởng đến form cũ của bạn.

🎨 Inconsistent Designs

  • Các file PSD không đồng bộ ➔ Mỗi người QA hoặc Designer dùng 1 phiên bản khác nhau để so sánh.

🧠 Waffling Decision Makers

  • Quy luật xác suất vô hạn: Càng nhiều tính năng, càng nhiều người duyệt ➔ chắc chắn sẽ có thay đổi.
  • Không phân biệt giữa change requestdefect ➔ Tốn thời gian vô ích.

🛡️ Giải pháp: Visual Regression Testing

🌟 Visual Regression Testing giúp:

  • Chụp ảnh giao diện đã được duyệt (baseline).
  • So sánh ảnh với phiên bản mới ➔ Xác định khác biệt pixel.

🌟 Lợi ích:

  • Có bằng chứng rõ ràng: nếu baseline không thay đổi, lỗi thuộc về file PSD.
  • Phân biệt rõ bug thực sựchange request ngẫu hứng.

📸 Các dạng Visual Regression Testing

🧱 Page-based Diffing

  • Ví dụ: Wraith
  • Cách hoạt động:
    • So sánh toàn bộ trang web giữa 2 môi trường (live vs staging).
  • Phù hợp: Khi không kỳ vọng có sự khác biệt.

📦 Component-based Diffing

  • Ví dụ: BackstopJS
  • Cách hoạt động:
    • Chụp và so sánh từng phần tử nhỏ (selectors) thay vì toàn trang.
  • Ưu điểm: Tránh false positive khi nội dung khác làm dịch bố cục.

🎯 CSS Unit Testing

  • Ví dụ: Quixote
  • Cách hoạt động:
    • Kiểm tra giá trị CSS (font-size, margin, v.v.) thay vì hình ảnh.
  • Ưu điểm: Rất mạnh khi kiểm soát branding, bố cục chuẩn xác.

🖥️ Headless Browser Driven

  • Ví dụ: Gemini + PhantomJS
  • Cách hoạt động:
    • Sử dụng trình duyệt không giao diện để tải và chụp ảnh website.
  • Ưu điểm: Nhanh, nhất quán, phù hợp automation.

🖥️ Desktop Browser Driven

  • Ví dụ: Gemini + Selenium
  • Cách hoạt động:
    • Chạy tests trên trình duyệt thật (Chrome, Firefox, v.v.).
  • Ưu điểm: Bắt được các lỗi mà chỉ xuất hiện trên trình duyệt cụ thể.

🛠️ Includes Scripting Libraries

  • Ví dụ: CasperJS
  • Cách hoạt động:
    • Tương tác như người dùng: hover, click, fill form rồi chụp ảnh.
  • Ưu điểm: Test được các luồng động và dữ liệu thay đổi.

🖼️ GUI-based Comparison & Approval

  • Ví dụ: Diffux
  • Cách hoạt động:
    • Có giao diện web để xem kết quả và duyệt/reject thay đổi hình ảnh.
  • Ưu điểm: Cho phép người không kỹ thuật tham gia kiểm tra.

💻 Command-line Comparison & Approval

  • Ví dụ: PhantomCSS
  • Cách hoạt động:
    • Chạy kiểm tra bằng lệnh terminal ➔ Kết quả pass/fail ngay trong terminal.
  • Ưu điểm: Tích hợp dễ dàng vào hệ thống CI/CD như Jenkins, Travis CI.

🔥 Kết luận

  • Visual Regression Testing:
    • Làm giảm đáng kể số lượng lỗi giao diện ngẫu nhiên.
    • Bảo vệ thiết kế khỏi những thay đổi không mong muốn.
    • Tiết kiệm thời giannâng cao uy tín khi đối mặt với QA và stakeholders.

Để lại một bình luận