Debug lỗi hiệu quả trong test automation

Debug lỗi hiệu quả trong test automation

Xem nhanh

Là một người chịu trách nhiệm bảo trì hệ thống test automation, sẽ có lúc bạn phát hiện hệ thống báo lỗi (error). Vậy bạn cần làm những gì để phục hồi lại hệ thống test automation một cách nhanh nhất? Debug lỗi sẽ giúp bạn giải quyết vấn đề cũng như xác định được bug xảy ra của sản phẩm test hay do logic test code. Bài viết này chia sẻ lại một số kinh nghiệm về debug lỗi mà tôi đúc kết được trong quá trình xử lý lỗi trên hệ thống test automation của Cybozu Việt Nam.

Quy trình hoạt động của hệ thống Garoon test automation

Nội dung bài viết được dựa trên trải nghiệm thực tế khi tôi làm việc với dự án test automation cho sản phẩm Garoon, một sản phẩm chủ đạo của Cybozu. Do đó, trước khi đi vào chi tiết về quy trình chung để xử lý lỗi, phần này tôi xin giới thiệu lại quy trình hoạt động của hệ thống Garoon test automation.

Việc nắm rõ sơ đồ hoạt động của hệ thống sẽ phần nào giúp bạn xác định và xử lý lỗi nhanh chóng hơn. Trong phạm vi bài viết này, các ví dụ đều liên quan trực tiếp đến sơ đồ hoạt động bên dưới:

Hình-01: Quy trình hoạt động của hệ thống test automation.

Hình-01: Quy trình hoạt động của hệ thống test automation.

Từ hình-01, bạn có thể thấy hệ thống test automation gồm có nhiều bước thực hiện:

  • Bước thiết lập môi trường test: build docker, vagrant, máy ảo, v.v
  • Bước thiết lập testing site
  • Bước thực hiện test
  • Bước report kết quả

Ở mỗi bước, lỗi đều có thể xảy ra. Tuy nhiên các lỗi về môi trường thường không thường xuyên xảy ra khi hệ thống đã đi vào ổn định. Trong khi đó, trong quá trình bảo trì hệ thống, bạn sẽ thường gặp lỗi ở bước “Thực hiện test“. Do đó, trong phần quy trình chung để xử lý lỗi, tôi chủ yếu tập trung vào phân tích lỗi xảy ra tại bước này.

Quy trình chung để xử lý lỗi

Để debug lỗi hiệu quả, phần này tôi trình bày về quy trình chung để xử lý lỗi. Bạn có thể thực hiện một số bước như sau để khoanh vùng và xử lý lỗi:

  • Xác định xem lỗi nằm ở bước nào trong quy trình hoạt động của hệ thống
  • Phân tích lỗi từ test reporter tools
  • Phân tích lỗi từ các log tools
  • Xử lý một số lỗi thường gặp và cách phòng tránh

Chi tiết của từng bước được trình bày bên dưới:

1. Xác định xem lỗi nằm ở bước nào trong quy trình hoạt động của hệ thống

Theo quy trình hoạt động ở hình-01, các quá trình hoạt động tuần tự. Do đó, chúng ta có thể dễ dàng khoanh vùng được hệ thống đang bị lỗi ở bước nào dựa vào output trên CI tool. Việc khoanh vùng này rất quan trọng vì nó giúp thu hẹp phạm vi tìm kiếm nguyên nhân lỗi. Khoanh vùng sẽ giúp bạn xác định đúng kiến thức nào cần thiết cho việc xử lý lỗi.

Ví dụ:

  • Bạn sử dụng Docker trong bước thiết lập môi trường. Lỗi xảy ra ở bước này. Vậy thì bạn cần dùng tài liệu, kiến thức về Docker để debug tiếp theo.
  • Lỗi xảy ra tại bước thực hiện test. Chúng ta cũng có thể phán đoán được các thành phần liên quan đến thực thi test: lỗi có thể do automation framework, assertion library, test code hay bug của product, v.v.

Hình-02: Kết quả thực hiện ở mỗi phần của hệ thống trên CircleCI

Hình-02: Kết quả thực hiện ở mỗi phần của hệ thống trên CircleCI

Như bạn thấy ở hình-02, CircleCI hiển thị lỗi xảy ra tại bước thực hiện test. Với những công cụ CI hỗ trợ khoanh vùng lỗi như vậy sẽ giúp bạn tiết kiệm được thời gian xác định lỗi.

2. Phân tích lỗi từ report tool

Với “Xác định xem lỗi nằm ở bước nào trong quy trình hoạt động của hệ thống”, cho chúng ta thấy được nơi xuất phát lỗi nằm ở bước nào trong quy trình hoạt động. Nhưng để biết được chi tiết hơn về lỗi xảy ra, bạn cần phân tích lỗi từ report tool.

Thông thường thì các report tool sẽ hỗ trợ liệt kê ra danh sách kết quả của các test case với trạng thái passed hoặc failed. Từ đó, chúng ta có thể biết chính xác được test case xảy ra lỗi.

Dưới đây là ví dụ về kết quả lỗi được report tool in ra:

Hình-03: Kết quả lỗi từ Spec Reporter

Hình-03: Kết quả lỗi từ Spec Reporter
// Nội dung lỗi:
The field  "ForceUserChangePasswordCheckbox" is not disabled yet: expected false to be true

// Code file nào đang gây ra lỗi:
**/cloud/security-setting.spec.js:26:18  

Ngày nay có rất nhiều công cụ hỗ trợ cho việc report kết quả test, ví dụ: JUnit, Allure, Report portal, v.v. Để hiểu rõ hơn về các reporter tool, mời các bạn tham khảo bài viết: Test Report: Tầm quan trọng và tiêu chí lựa chọn report tool phù hợp.

3. Phân tích lỗi từ các log tools

Sau khi xác định được nơi xảy ra lỗi từ report tool ở bước trên, việc tiếp theo là chúng ta cần phải xác định được nguyên nhân cụ thể vì sao lỗi lại xảy ra. Nhiều khi thông tin lỗi từ report tool không miêu tả được nguyên nhân thực sự gây ra lỗi.

Ví dụ ở hình-03, report tool thể hiện nơi đang xảy ra lỗi với nội dung như sau:

The field "ForceUserChangePasswordCheckbox" is not disabled yet: expected false to be true

Nhưng để sửa được lỗi chúng ta cần đi tìm nguyên nhân vì sao kết quả mong muốn lại khác kết quả thực đang hiển thị trên ứng dụng.

Có hai tình huống xảy ra ở trường hợp này:

  • Lỗi của sản phẩm ở tại bước thực hiện này của test code: màn hình không hiển thị đúng.
  • Lỗi sinh ra do những bước thực hiện trước đó không đúng.

Vì vậy chúng ta cần phải dựa vào thông tin từ log trong quá trình chạy để xác định chính xác nguyên nhân lỗi thực sự.

Các log tool hiện nay được biết dưới hai dạng: hiển thị UI (UI log) và dạng text (text log).

  • UI log: chúng ta có thể dùng hình ảnh chụp màn hình, hình ảnh động dạng Gif hoặc video để theo dõi quá trình chạy test.
  • Text log: log hiển thị dạng văn bản. Hầu hết các automation framework đều hỗ trợ mặc định dạng log này, ví dụ dưới đây là một đoạn text log của WebdriverIO framework:
[0-0] 2021-07-19T10:41:03.491Z INFO webdriver: COMMAND findElement("xpath", "//*[@class="login-button"]")
[0-0] 2021-07-19T10:41:03.491Z INFO webdriver: [POST] http://localhost:4444/wd/hub/session/1e1603e1f2f2778716fb08e8a6698fbf/element
[0-0] 2021-07-19T10:41:03.491Z INFO webdriver: DATA { using: 'xpath', value: '//*[@class="login-button"]' }
[0-0] 2021-07-19T10:41:03.515Z INFO webdriver: RESULT {
[0-0]   error: 'no such element',
[0-0]   message: 'no such element: Unable to locate element: {"method":"xpath","selector":"//*[@class="login-button"]"}\n' +
[0-0]     '  (Session info: chrome=89.0.4389.82)',
[0-0]   stacktrace: '#0 0x5638264c02b9 <unknown>\n'
[0-0] }
[0-0] 2021-07-19T10:41:03.516Z DEBUG @wdio/sync: Finished to run "afterCommand" hook in 0ms

Ngoài ra, đối với text log mặc định của các framework (ví dụ: Selenium webdriver, webdriverIO), chúng thường rất khó hiểu, và mất thời gian để tìm hiểu, chúng ta có thể xây dựng các phương thức hiển thị log riêng cho hệ thống của mình, chi tiết có thể xem thêm ở bài viết: System log và custom log trong automation testing.

Đối với những lỗi phức tạp, đôi khi chúng ta cần kết hợp thông tin của cả UI log và text log để xác định nguyên nhân lỗi chính xác hơn. Như trong ví dụ trên, chúng ta có log dạng text như sau:

[0-0]   error: 'no such element',
[0-0]   message: 'no such element: Unable to locate element: {"method":"xpath","selector":"//*[@class="login-button"]"}\n' +
[0-0]     '  (Session info: chrome=89.0.4389.82)',
[0-0]   stacktrace: '#0 0x5638264c02b9 <unknown>\n'

Những lỗi kiểu này thì nếu chỉ check UI log sẽ không hiểu được chuyện gì đang xảy ra. Vì lỗi này xảy ra trong quá trình xử lý của chương trình, trên UI chỉ screenshot được nơi xảy ra lỗi không thể hiện được nội dung lỗi khi chương trình throw error. Còn những lỗi như nhập sai giá trị, truy cập sai màn hình thì hoàn toàn có thể check nhanh bằng UI log.

4. Xử lý một số lỗi thường gặp và cách phòng tránh

Sau khi xác định được nguyên nhân lỗi thì việc cuối cùng là sửa lỗi để hệ thống hoạt động trở lại bình thường. Sau đây là một số lỗi thường gặp và cách xử lý:

  • Lỗi sản phẩm, đối với những lỗi này chúng ta cần phải test lại bằng manual testing để đảm bảo chắc chắn và cần phải báo cho team phát triển sản phẩm để thực hiện việc sửa lỗi.

  • Thay đổi locator do sản phẩm được cập nhật mới, dẫn đến source code automation cho tính năng này không còn đúng và chạy bị lỗi.
    Ví dụ:

    • xpath locator cũ: '//*[@id="test"]/table/tbody/div/a'
    • xpath locator mới: '//*[@id="test"]/table/tbody/div/div/a'

    Với lỗi này, thông thường bạn sẽ phải sửa lại automation code cho phù hợp với sự thay đổi của sản phẩm test. Để hạn chế việc xảy ra lỗi này, chúng ta nên có một chiến lược để tạo locator một cách hợp lý. Với ví dụ trên, bạn có thể sử dụng locator dạng //*[@id="test"]//a[text()="abc"], sẽ tránh được lỗi xảy ra.

  • Lỗi phát sinh do bị ảnh hưởng bởi các test code mới. Các test script thường được thiết kế theo hướng tối ưu, tái sử dụng nên việc các module liên quan tới nhau cũng dễ hiểu. Chính vì vậy, khi chúng ta sửa một logic được dùng ở nhiều module nhưng cập nhật không triệt để ở những nơi liên quan thì sẽ có khả năng xảy ra lỗi. Để hạn chế những lỗi này, chúng ta nên tham khảo thêm các nguyên lý Solid hoặc cách thiết kế mới được giới thiệu trong bài: Folder-by-feature structure: Cấu trúc tổ chức mã nguồn e2e testing quy mô lớn

  • Môi trường không ổn định, với những lỗi này chúng ta thường phải thực hiện test lại nhiều lần để tái hiện lỗi. Nguyên nhân chính có thể do hiệu suất của sản phẩm không tốt, hiệu suất của môi trường thực hiện test không ổn định (máy ảo, Docker xử lý chậm), đường truyền internet không ổn định dẫn đến chương trình không tìm được các locator để tương tác, v.v.
    Để hạn chế những lỗi này chúng ta nên dùng các cơ chế “chờ”.
    Ví dụ: framework WebdriverIO cung cấp cho bạn một số cơ chế chờ: Auto-waiting, waitForExist, waitForEnable. Sau khi các web element sẵn sàng chúng ta sẽ thực hiện hành động tiếp theo.

  • Lỗi liên quan đến các framework, lib, tool. Có thể do các framework đang được sử dụng có tiềm ẩn lỗi bên trong. Ngoài ra cũng có khả năng chúng ta triển khai chưa đúng với những yêu cầu không được mô tả rõ ràng trong tài liệu của framework. Với những lỗi này, chúng ta nên tận dụng các kênh trao đổi ngoài cộng đồng có liên quan đến các framework đó để cách sửa lỗi nhanh hơn. Ví dụ về các issue của WebdriverIO, Selenium.

Chúng ta nên thực hiện 4 bước trên để debug và sửa lỗi hiệu quả.

Ví dụ: chúng ta có một lỗi với thông tin như sau

[#0-0] 
       ErrorCode: ERR_PAGE_INTERACTION
       Error: BaseElement->element: Error: element ("span=Inbox") still not displayed after 5000ms
       Cause: 
       Try: Try to check the https://example.com testing site provided is working normally
       Selector: span=Inbox

Lỗi này được hiểu là chương trình không thể tìm thấy được locator "span=Inbox" ở một trang của ứng dụng. Có rất nhiều nguyên nhân dẫn đến lỗi này. Ở đây, giả sử nguyên nhân chính của lỗi này là do môi trường không ổn định. Trong trường hợp này, nếu bạn không thực hiện bước 3 để tìm hiểu nguyên nhân cụ thể mà chỉ nhìn vào report ở bước 2, sau đó sửa test code theo hướng cập nhật lại locator, thì vẫn có khả năng lỗi vẫn tiếp tục xảy ra ở lần chạy test sau. Thực hiện theo các bước của quy trình xử lý lỗi sẽ đảm bảo cho việc xác định đúng nguyên nhân lỗi và xử lý nhanh chóng hơn.

Ngoài ra, chúng ta có thể kết hợp một số kỹ thuật debug thông dụng khác như: console.log(), throw error (với JavaScript), để xem “luồng” xử lý của chương trình hay in ra các giá trị của tham số, kết quả trả về của function. Từ đó, chúng ta có thể phán đoán nguyên nhân lỗi.

Kết

Việc sử dụng phương pháp điều tra, sửa lỗi như thế nào sẽ phụ thuộc nhiều vào kỹ năng và kinh nghiệm của mỗi người. Bài viết trình bày 4 bước tiến hành mà tôi thường dùng, giúp tôi có cái nhìn tổng quát về lỗi cũng như sửa lỗi hiệu quả, chính xác.

Ngoài ra, việc sửa lỗi dễ hay khó còn phụ thuộc nhiều vào các yếu tố khác như cách thiết kế hệ thống test automation, thiết kế test code (code structure), cách hiển thị log, v.v. Vậy nên người thiết kế, viết test code nên có tư duy “hướng” về phía người bảo trì hệ thống, giúp người bảo trì thuận tiện hơn trong quá trình sửa lỗi phát sinh ở giai đoạn sau.