Mocha run cycle? Những điều cần biết cho người mới bắt đầu

Mocha run cycle? Những điều cần biết cho người mới bắt đầu

Xem nhanh

Mocha là một testing Framework chạy trên Node.js. Mocha có nhiều chức năng hỗ trợ giúp việc viết test script đơn giản, linh hoạt được nhiều người đón nhận. Hiện tại Cybozu Vietnam cũng đang sử dụng Mocha để triển khai hệ thống end-to-end testing.

Trong nhiều đặc trưng của Mocha framework thì run cycle là một đặc trưng quan trọng. Để hiểu cặn kẽ về nó có lẽ cũng vất vả và tốn kha khá thời gian. Do đó trong bài viết này tôi muốn chia sẻ về mocha run cycle sau những trải nghiệm sử dụng Mocha cho kiểm thử tự động tại Cybozu Vietnam. Tôi hy vọng bài viết này sẽ giúp chúng ta sử dụng mocha run cycle hiệu quả nhất.

Các code snippet trong bài viết được thực hiện trên Mocha version 8.3.0. Để xem chi tiết toàn bộ source code vui lòng truy cập vào đây.

Nội dung trong bài sẽ trình bày mocha run cycle theo hai chế độ:

  1. Chế độ chạy tuần tự
  2. Chế độ chạy song song

1. Chế độ chạy tuần tự

Chế độ chạy tuần tự: Mocha scan tất cả các test spec [1], sau đó đưa tất cả các root hook, test suite (gồm test cases và hooks) vào một suite duy nhất gọi là root suite. Sau đó, Mocha tiến hành thực thi root suite.

Phần tiếp theo dưới đây sẽ trình bày chi tiết về chế độ chạy tuần tự trong Mocha.

Sơ đồ Mocha run cycle

Copy
execute mocha
|
[step 1] load options from config file (.mocharc.js, .mocharc.yml, etc)
|
[step 2] process arguments specified on command-line
|
[step 3] spawn child process If known flags for the node executable are found
|
[step 4] loads modules specified by --require
|
[step 5] validates any custom reporters or interfaces which were loaded via --require or otherwise
|
[step 6] discovers test files
|
[step 7] runs global setup fixtures, if any
|
[step 8] starting root suite
|
'beforeAll' root-hooks 
|--------------> per each test suite (describe)
    
    'before' hooks
    |
    |<-------------- per each test case (it)
    'beforeEach' root-hooks
    |
    'beforeEach' hooks
    |
    The test (and reports the result)
    |
    'afterEach' hooks
    |
    'afterEach' root-hooks
    |<-------------- per each test case (it)
    |
    'after' hooks
|<-------------- per each test suite (describe) end
'afterAll' root-hooks 
|
[step 9] prints a final summary/epilog, if applicable
|
[step 10] runs global teardown fixtures, if any

Giải thích trình tự thực thi của sơ đồ

  1. [step 1] load options from config file (.mocharc.js, .mocharc.yml, etc)
    Thực hiện tải các file cấu hình (.mocharc.js, .mocharc.yml, etc) nếu có. Có nhiều cách khác nhau để cấu hình cho Mocha. Xem thêm tại đây. Bạn có thể chỉ định file cấu hình bằng cách như sau:

    Copy
    npm test --config './.mocharc.js' test.js
  2. [step 2] process arguments specified on command-line
    Xử lý các tham số được chỉ định từ command-line. Dưới đây là một ví dụ về trường hợp truyền tham số từ command-line để chạy toàn bộ các file kết thúc với '.js' trong folder 'spec':

    Copy
    npm test --recursive "./spec/*.js"
  3. [step 3] spawn child process If known flags for the node executable are found
    Ngoài các tham số riêng của Mocha thì từ command-line hay file cấu hình bạn có thể truyền vào các tham số của Nodejs hỗ trợ (gọi chung là node flags). Mocha hỗ trợ thực thi tất cả các node flags của Node. Bạn cần lưu ý version của Node mà mình đang sử dụng là gì để truyền vào các flags phù hợp với version đó.

    Khi node flags được tìm thấy, mocha sẽ thực hiện “spawn node in a child process” để thực thi các node flags này. Có lẽ bạn sẽ cảm thấy khá bối rối với cụm từ “spawn child process“. Nó liên quan đến một tính năng mà Node hỗ trợ cho phép thực thi chức năng nào đó trên một tiến trình con mới. Bạn có thể tìm hiểu thêm về “spawn child process“ và lý do tại sao Node lại cung cấp cơ chế này tại đây.

  4. [step 4] loads modules specified by --require
    Tải các module được chỉ định bởi --require. Dưới đây là một ví dụ tải file hook.js bằng --require. File này chứa các root hooks. Ngoài cách tải lên bằng --require thì bạn hoàn toàn có thể chỉ định tải file này lên trong config file.

    Copy
    npm test --require hook.js spec/test1.js
  5. [step 5] validates any custom reporters or interfaces which were loaded via --require or otherwise

    Xác nhận lại các custom reporter hoặc các interfaces [2] được tải lên bởi --require hay bằng cách khác.

  6. [step 6] discovers test files

    Tại bước này Mocha thực hiện "khám phá" các test files. Trong trường hợp chúng ta không chỉ định rõ test file hay test folder thì Mocha sẽ mặc định tìm file với định dạng .js, .mjs hoặc.cjs trong folder test (không bao gồm thư mục con của test).

    Mặc định, Mocha sẽ load các test file không có thứ tự. Với chế độ chạy tuần tự, tất cả các test case (it) và suites (describe) sẽ được quản lý chung bởi duy nhất một "root suite". Chúng ta có thể hiểu "root suite" như một hàng đợi mà Mocha tự đặt các tests và suites vào trong quá trình "khám phá" các test files.

    Sau đó, ở [step 8], Mocha sẽ thực hiện thực thi "root suite" này.

  7. [step 7] runs global setup fixtures, if any
    Thực thi global setup fixtures nếu có. File này thường thiết lập liên quan đến việc khởi động server, mở socket….

  8. [step 8] starting root suite
    Như đã đề cập ở [step 6] thì ở chế độ tuần tự, Mocha quản lý tất cả trong một "root suite" duy nhất. Ở step này, Mocha tiến hành thực thi các tests nằm trong root suite. Đây cũng là bước mà chúng ta quan tâm nhất, bước này thể hiện thứ tự thực hiện các hook [3] trong Mocha.

    Trước khi đi vào chi tiết, chúng ta cần phân biệt về root hooks và hooks:

    • root hooks: được define ở bên ngoài test file. Chúng thường được sử dụng khi bạn có nhu cầu thực hiện một số hành vi giống nhau cho mỗi test file (trước hoặc sau khi thực thi test file).
    • hooks: được define ở bên trong test file. Chính vì vậy, chúng chỉ được thực thi khi test file chứa chúng được thực thi.

    Trình tự thực hiện theo thứ tự như sau:
    'beforeAll' root-hooks thực thi 1 lần duy nhất cho cả root suite
    'before' hooks của suite con bên trong root suite: thực thi 1 lần trước khi test case đầu tiên của suite con được thực thi
    'beforeEach' root-hooks thực thi trước khi mỗi test case của mỗi test suite được thực thi
    'beforeEach' hooks của suite con bên trong root suite: thực thi trước khi mỗi test case được thực thi
    The test case thực thi test case (it), trong một test suite có thể có 1 hay nhiều test case.
    'afterEach' hooks của suite con bên trong root suite: thực thi sau khi mỗi test case được thực thi
    'afterEach' root-hooks thực thi sau mỗi test case của mỗi test suite được thực thi
    'after' hooks của suite con bên trong root suite: thực thi 1 lần sau khi test case cuối cùng của suite con được thực thi
    'afterAll' root-hooks thực thi 1 lần duy nhất cho cả root suite

  9. [step 9] prints a final summary/epilog, if applicable
    In ra tóm tắt cuối cùng nếu được yêu cầu

  10. [step 10] runs global teardown fixtures, if any
    Thực thi global teardown fixtures, nếu có. File này thường thiết lập các công việc sau khi Mocha đã hoàn thành việc kiểm thử như tắt server chẳng hạn.

2. Chế độ chạy song song

Với chế độ chạy song song, Mocha có thể thực thi nhiều test files đồng thời với nhau, mỗi test file được thực thi trên một process khác nhau.

Sơ đồ Mocha run cycle

Copy
execute mocha
|
[step 1] load options from config file (.mocharc.js, .mocharc.yml, etc)
|
[step 2] process arguments specified on command-line
|
[step 3] spawn child process If known flags for the node executable are found
|
[step 4] loads modules specified by --require
|
[step 5] All test files found are put into a queue (they are not loaded by the main process)
|
[step 6] runs global setup fixtures, if any
|
[step 7] Mocha creates a pool of subprocesses (“workers”)
|
[step 8] The worker “bootstraps” itself
|
[step 9] Worker execute test files
|--------------> per workers
[step 9.1] The worker creates a new Mocha instance for the single test file
|
[step 9.2] execute the test files
|--------------> per test file
    'beforeAll' root-hooks
    |
    'before' hooks
    |
    |--------------> per test
      'beforeEach' root-hooks
      |
      'beforeEach' hooks
      |
      The test (the worker does not report test results directly)
      |
      'afterEach' hooks
      |
      'afterEach' root-hooks
    |<-------------- per test end
    |
    'after' hooks
    |
    'afterAll' root-hooks
|<-------------- per test file end
[step 9.3] results are returned to the main process, which then gives them to the user-specified reporter (spec by default)
|
[step 9.4] worker makes itself available to the pool, repeat [step 9.2] if any remain spec file
|<-------------- per workers end
[step 10] prints a final summary/epilog, if applicable
|
[step 11] runs global teardown fixtures, if any

Giải thích trình tự thực thi của sơ đồ

  1. [step 1] - [step 4]:
    Giống với [step 1] - [step 4] của chế độ chạy tuần tự bên trên

  2. [step 5] All test files found are put into a queue (they are not loaded by the main process)
    Tất cả các test files được tìm thấy sẽ được đặt trong hàng đợi thay vì tải bằng main process [4]

  3. [step 6] runs global setup fixtures, if any
    Giống với [step 6] của chế độ chạy tuần tự bên trên

  4. [step 7] Mocha creates a pool of subprocesses (“workers”)
    Mocha sẽ tạo ra pool of subprocesses [5] (“workers”). Khi worker nhận một test file để chạy, worker này sẽ tạo ra một Mocha instance và thực thi test.

  5. [step 8] The worker “bootstraps” itself
    Trước khi thực thi test file đầu tiên, Worker sẽ khởi động và thực hiện:

    • Tải các module được chỉ định bởi --require
    • Đăng ký các root hooks
    • Bỏ qua các global fixtures và custom reporters
    • Validates các interfaces
  6. [step 9] Worker execute test files
    [step 9.1] The worker creates a new Mocha instance for the single test file
    Worker tạo Mocha instance để thực thi 1 test file
    [step 9.2] execute the test files
    Worker thực thi test file. Tương tự với [step 8] của chế độ chạy tuần tự bên trên. Tuy nhiên kết quả sẽ không báo cáo trực tiếp sau khi test case thực thi xong mà Worker sẽ giữ kết quả tại memory buffer [6]

    Ngoài ra, ở chế độ chạy tuần tự, tất cả các suites của các test files được đặt trong duy nhất một root suite để chạy lần lượt thì ở chế độ chạy song song, Mocha sẽ chạy độc lập các test files. Do đó, sự hoạt động của root hooks sẽ có sự thay đổi như sau:

    • 'beforeAll' root-hooks thực thi 1 lần trước mỗi test file
    • 'afterAll' root-hooks thực thi 1 lần sau mỗi test file


    [step 9.3] results are returned to the main process, which then gives them to the user-specified reporter (spec by default)
    Worker trả kết quả về cho main process sau khi test file hoàn thành. Kết quả này được đưa về cho reporter mà người dùng chỉ định hoặc mặc định.
    [step 9.4] worker makes itself available to the pool, repeat [step 9.2] if any remain spec file
    Worker thông báo trạng thái available của mình đến pool [7] để nhận test file mới nếu còn. Và tiếp tục lặp lại các bước từ 9.2 đến 9.4 cho đến khi không còn nhận được test file mới từ pool.

  7. [step 10] - [step 11]
    Giống với [step 8] - [step 9] của chế độ chạy tuần tự bên trên

Lời kết

Mocha run cycle gồm khá nhiều quá trình xử lý cho việc tải các config, report hay xử lý cho việc chạy song song…. Hi vọng qua bài viết này các bạn đã có cái nhìn tổng thể về cách mà Mocha thực thi các test spec.

Một số thuật ngữ sử dụng trong bài viết

[1] test spec: là file test script chứa kịch bản các test case sẽ được thực thi.

[2] interface: Mocha cung cấp các dạng BDD, TDD, Exports, QUnit và Require-style interfaces. Để biết thêm chi tiết vui lòng xem tại đây.

[3] hook: Đây là từ mà Mocha dùng để gọi chung cho before(), after(), beforeEach(), và afterEach().

[4] main process: tiến trình chính của Mocha. Trong trường hợp không phát sinh ra các tiến trình con thì đây là nơi xử lý toàn bộ run cycle của Mocha.

[5] pool of subprocesses: tập hợp các tiến trình con, nhận và thực thi các test spec

[6] memory buffer: bộ nhớ đệm. Là vùng lưu trữ dữ liệu tạm thời trong khi chờ để được chuyển đến một vị trí khác.

[7] pool: nơi quản lý các tiến trình con, làm nhiệm vụ điều phối các test spec đến các tiến trình con, nhận báo cáo trả về

Tài liệu tham khảo

https://mochajs.org/#run-cycle-overview

Các bài viết cùng chủ đề