Kiểm tra mã Node.js với Mocha và Chai

Giới thiệu

Tuy nhiên, viết bài kiểm thử đơn vị là việc mà những người mới bắt đầu cũng như các kỹ sư dày dạn kinh nghiệm thường trì hoãn cho các giai đoạn phát triển sau này - chúng là chìa khóa để phát triển phần mềm ổn định và mạnh mẽ.

Tiền đề cơ bản của phát triển dựa trên thử nghiệm (TDD) đang viết bài kiểm tra của bạn ngay cả trước khi bạn bắt đầu viết mã. Đó là một mục tiêu tuyệt vời để phấn đấu, nhưng cần rất nhiều kỷ luật và lập kế hoạch khi bạn cố gắng tuân theo các nguyên tắc của nó! Để làm cho toàn bộ quá trình này dễ dàng hơn nhiều, bạn có thể sử dụng các khung kiểm tra và xác nhận mạnh mẽ và dễ sử dụng, chẳng hạn như một thứ mã nảoChai.

Trong bài viết này, chúng tôi sẽ bắt đầu bằng cách giới thiệu cho bạn hai thư viện này, sau đó chỉ cho bạn cách sử dụng chúng cùng nhau để nhanh chóng tạo các bài kiểm tra đơn vị chức năng và dễ đọc.

Chai

Chai là một thư viện xác nhận cung cấp cả BDD (phát triển theo định hướng hành vi)TDD (phát triển dựa trên thử nghiệm) phong cách lập trình để kiểm tra mã và được kết hợp với thư viện kiểm tra cho phép bạn tổ chức các bài kiểm tra. Nó rất thường được kết hợp với Mocha.

Nó có ba API chính:

  • should
  • expect
  • assert

var.should.equal(var2)


expect.var.to.be.equal(var2)


assert.equal(var1, var2)

Trong suốt bài viết này, chúng tôi sẽ tập trung vào phong cách BDD bằng cách sử dụng Chai's expect giao diện, mặc dù việc sử dụng các giao diện/kiểu dáng khác theo trực giác của bạn là hoàn toàn ổn. Các assert giao diện là khung xác nhận TDD phổ biến nhất.

expect sử dụng API ngôn ngữ rất tự nhiên để viết các xác nhận của bạn, điều này sẽ giúp các bài kiểm tra của bạn dễ viết hơn và cải thiện sau này. Điều này được thực hiện bằng cách kết nối các getter lại với nhau để tạo và thực thi xác nhận, giúp việc dịch các yêu cầu thành mã dễ dàng hơn:

let user = {name: 'Scott'};


expect(user).to.have.property('name');

Lưu ý: Hãy xem làm thế nào bạn có thể đọc được phần khẳng định bằng ngôn ngữ tự nhiên và hiểu chuyện gì đang xảy ra? Đó là một trong những lợi thế chính của việc sử dụng thư viện xác nhận như Chai!

Một vài ví dụ khác về những getters này là:

  • to
  • be
  • is
  • and
  • has
  • have

Khá nhiều trong số các getter này có thể được nối lại với nhau và được sử dụng với các phương thức xác nhận như true, ok, existempty để tạo một số xác nhận phức tạp chỉ trong một dòng:

"use strict";

const expect = require('chai').expect;


expect({}).to.exist;
expect(26).to.equal(26);
expect(false).to.be.false;
expect('hello').to.be.string;


expect([1, 2, 3]).to.not.be.empty;


expect([1, 2, 3]).to.have.length.of.at.least(3);

Lưu ý: Một danh sách đầy đủ các phương pháp có sẵn có thể được tìm thấy tại đây.

Bạn cũng có thể muốn xem danh sách có sẵn bổ sung cho Chai. Những điều này giúp việc kiểm tra các tính năng phức tạp hơn dễ dàng hơn nhiều.

Hãy chai-http ví dụ: đây là plugin giúp bạn kiểm tra các tuyến máy chủ:

"use strict";

const chai = require('chai');
const chaiHttp = require('chai-http');

chai.use(chaiHttp);

chai.request(app)
    .put('/api/auth')
    .send({username: '[email protected]', password: 'abc123'})
    .end(function(err, res) {
        expect(err).to.be.null;
        expect(res).to.have.status(200);
    });

Tổ chức các trường hợp thử nghiệm với Mocha – mô tả() và it()

Mocha là một khung thử nghiệm cho Node mang lại cho bạn sự linh hoạt để chạy mã không đồng bộ (hoặc đồng bộ) một cách tuần tự. Mọi ngoại lệ chưa được phát hiện đều được hiển thị cùng với trường hợp thử nghiệm mà nó được đưa ra, giúp dễ dàng xác định chính xác điều gì không thành công và tại sao.

Bạn nên cài đặt Mocha trên toàn cầu:

$ npm install mocha -g

Bạn sẽ muốn nó được cài đặt toàn cầu vì mocha lệnh được sử dụng để chạy thử nghiệm cho dự án trong thư mục cục bộ của bạn.

Đoạn mã này làm gì?

it() nên trả về X. it() xác định các trường hợp thử nghiệm và Mocha sẽ chạy từng trường hợp thử nghiệm it() như một bài kiểm tra đơn vị. Để tổ chức nhiều bài kiểm tra đơn vị, chúng ta có thể describe() một chức năng chung và do đó cấu trúc các bài kiểm tra Mocha.

Điều này có lẽ được mô tả tốt nhất bằng một ví dụ cụ thể:

"use strict";
const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });
    });
});

Trong tạp chí describe() phương pháp, chúng tôi đã xác định một tên bài kiểm tra, Được gọi là #abs(). Bạn cũng có thể chạy thử nghiệm riêng lẻ theo tên của chúng - điều này sẽ được đề cập sau.

Lưu ý: Với các bài kiểm tra Mocha, bạn không cần phải require() bất kỳ phương pháp Mocha nào. Các phương thức này được cung cấp trên toàn cầu khi chạy với mocha chỉ huy.

Để chạy các thử nghiệm này, hãy lưu tệp của bạn và sử dụng mocha chỉ huy:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given number 


  1 passing (9ms)

Đầu ra là bảng phân tích các thử nghiệm đã chạy và kết quả của chúng. Chú ý cách lồng nhau describe() các cuộc gọi được chuyển sang kết quả đầu ra. Sẽ rất hữu ích khi lồng tất cả các thử nghiệm cho một phương pháp hoặc tính năng nhất định vào với nhau.

Những phương pháp này là cơ sở cho khung thử nghiệm Mocha. Sử dụng chúng để soạn và sắp xếp các bài kiểm tra của bạn theo cách bạn muốn. Chúng ta sẽ thấy một ví dụ về điều này trong phần tiếp theo.

Viết bài kiểm tra với Mocha và Chai

Cách được khuyến nghị để tổ chức các bài kiểm thử trong dự án của bạn là đặt tất cả chúng vào một nhóm riêng. /test danh mục. Theo mặc định, Mocha kiểm tra các bài kiểm tra đơn vị bằng cách sử dụng các khối ./test/*.js./test/*.coffee. Từ đó, nó sẽ tải và thực thi bất kỳ tệp nào gọi tới describe() phương pháp.

Xem hướng dẫn thực hành, thực tế của chúng tôi để học Git, với các phương pháp hay nhất, các tiêu chuẩn được ngành công nghiệp chấp nhận và bảng lừa đảo đi kèm. Dừng lệnh Googling Git và thực sự học nó!

Người ta thường thêm hậu tố vào các tệp thử nghiệm bằng .test.js đối với các tệp nguồn có chứa các bài kiểm tra Mocha:

├── package.json
├── lib
│   ├── db.js
│   ├── models.js
│   └── util.js
└── test
    ├── db.test.js
    ├── models.test.js
    ├── util.test.js
    └── util.js

util.js trong test thư mục sẽ không chứa bất kỳ bài kiểm tra đơn vị nào, chỉ có các chức năng tiện ích để trợ giúp kiểm tra.

Chú thích: Bạn có thể sử dụng bất kỳ cấu trúc nào bạn thấy hợp lý, các bài kiểm tra đơn vị sẽ tự động được chọn.

Khi thực sự viết bài kiểm thử, việc tổ chức chúng bằng cách sử dụng describe() phương pháp. Bạn có thể sắp xếp chúng theo tính năng, chức năng, tệp hoặc bất kỳ cấp độ tùy ý nào khác. Ví dụ: một tệp thử nghiệm được tổ chức để mô tả hoạt động ở cấp chức năng trông như sau:

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });
});

Chạy thử nghiệm sau đó sẽ cung cấp cho bạn kết quả:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 


  3 passing (11ms)

Mở rộng hơn nữa, bạn thậm chí có thể có các bài kiểm tra cho nhiều phương pháp trong một tệp. Trong trường hợp này, các phương pháp được nhóm lại theo Math vật:

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });

    describe('#sqrt()', function() {
        it('should return the square root of a given positive number', function() {
            expect(Math.sqrt(25)).to.be.equal(5);
        });

        it('should return NaN for a given negative number', function() {
            expect(Math.sqrt(-9)).to.be.NaN;
        });

        it('should return 0 given 0', function() {
            expect(Math.sqrt(0)).to.be.equal(0);
        });
    });
});

Kết quả là:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  6 passing (10ms)

Móc Mocha – before(), after(), beforeEach() và afterEach()

Phải thừa nhận rằng hầu hết các bài kiểm tra đơn vị đều không đơn giản như vậy. Nhiều khi bạn có thể sẽ cần các tài nguyên khác để thực hiện thử nghiệm của mình, chẳng hạn như cơ sở dữ liệu hoặc một số tài nguyên bên ngoài khác (hoặc bản mô phỏng/sơ khai của chúng). Để thiết lập điều này, chúng ta có thể sử dụng một hoặc nhiều cách sau móc mocha phương pháp:

  • before(): Chạy trước tất cả các bài kiểm tra trong khối nhất định
  • beforeEach(): Chạy trước mỗi bài kiểm tra trong khối nhất định
  • after(): Chạy sau tất cả các bài kiểm tra trong khối nhất định
  • afterEach(): Chạy sau mỗi bài kiểm tra trong khối nhất định

Những chiếc móc này là nơi hoàn hảo để thực hiện công việc thiết lập và chia nhỏ cần thiết cho các bài kiểm tra của bạn. Một trong những trường hợp sử dụng phổ biến là thiết lập kết nối với cơ sở dữ liệu của bạn trước khi chạy thử nghiệm:

"use strict";

const expect = require('chai').expect;
let User = require('../models').User;

describe('Users', function() {

    let database = null;

    before(function(done) {
        
    });

    afterEach(function(done) {
        
    });

    describe('#save()', function() {
        it('should save User data to database', function(done) {
            
        });
    });

    describe('#load()', function() {
        it('should load User data from database', function(done) {
            
        });
    });
});

Trước bất kì trong số các bài kiểm tra được chạy, hàm sẽ được gửi tới before() phương thức được chạy (và chỉ chạy một lần trong suốt quá trình kiểm tra), thiết lập kết nối tới cơ sở dữ liệu. Sau khi hoàn thành việc này, bộ thử nghiệm của chúng tôi sẽ được chạy.

Vì chúng tôi không muốn dữ liệu từ một bộ thử nghiệm ảnh hưởng đến các thử nghiệm khác của mình nên chúng tôi cần xóa dữ liệu khỏi cơ sở dữ liệu sau khi mỗi bộ thử nghiệm được chạy. Đây là cái gì afterEach() là cho. Chúng tôi sử dụng hook này để xóa tất cả dữ liệu cơ sở dữ liệu sau mỗi trường hợp thử nghiệm đã được chạy, vì vậy chúng ta có thể bắt đầu từ một phương án rõ ràng cho các thử nghiệm tiếp theo.

Chạy thử nghiệm Mocha

Đối với phần lớn các trường hợp, phần này khá đơn giản. Giả sử bạn đã cài đặt Mocha và điều hướng đến thư mục dự án, hầu hết các dự án chỉ cần sử dụng lệnh mocha lệnh không có đối số để chạy thử nghiệm của họ:

$ mocha


  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  6 passing (10ms)

Điều này hơi khác so với các ví dụ trước đây của chúng tôi vì chúng tôi không cần cho Mocha biết vị trí thử nghiệm của chúng tôi. Trong ví dụ này, mã kiểm tra nằm ở vị trí dự kiến ​​của /test.

Tuy nhiên, có một số tùy chọn hữu ích mà bạn có thể muốn sử dụng khi chạy thử nghiệm. Ví dụ: nếu một số thử nghiệm của bạn không thành công, có thể bạn không muốn chạy toàn bộ bộ phần mềm mỗi khi thực hiện thay đổi. Đối với một số dự án, bộ thử nghiệm đầy đủ có thể mất vài phút để hoàn thành. Sẽ rất lãng phí thời gian nếu bạn thực sự chỉ cần chạy một bài kiểm tra.

Với những trường hợp như thế này, bạn nên bảo Mocha nên chạy thử nghiệm nào. Điều này có thể được thực hiện bằng cách sử dụng -g or -f tùy chọn.

Để chạy thử nghiệm riêng lẻ, bạn có thể cung cấp -g gắn cờ và thêm mẫu chung giữa các thử nghiệm bạn muốn chạy. Ví dụ: nếu bạn muốn chạy #sqrt() kiểm tra:

$ mocha -g sqrt

  Math
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  3 passing (10ms)

Chú ý rằng #abs() các bài kiểm tra không được bao gồm trong lần chạy này. Nếu bạn lập kế hoạch phù hợp với tên bài kiểm tra của mình, tùy chọn này có thể được sử dụng để chỉ chạy các phần cụ thể của bài kiểm tra.

Tuy nhiên, đây không phải là những lựa chọn hữu ích duy nhất. Dưới đây là một số tùy chọn khác cho Mocha mà bạn có thể muốn xem:

  • --invert: Đảo ngược -g-f diêm
  • --recursive: Bao gồm các thư mục con
  • --harmony: Kích hoạt tất cả các tính năng hòa âm trong Node

Chú thích: Bạn có thể kiểm tra danh sách đầy đủ các tùy chọn bằng cách sử dụng mocha -h lệnh, hoặc trên trang này.

Tìm hiểu thêm ở đâu? Còn nhiều điều về chủ đề này hơn những gì chúng tôi có thể trình bày trong một bài viết ngắn, vì vậy nếu bạn muốn tìm hiểu thêm thì chúng tôi khuyên bạn nên xem trang chính thức một thứ mã nảoChai tài liệu hướng dẫn.

Kết luận

Hãy nhớ rằng cả Mocha và Chai đều có thể được sử dụng để thử nghiệm bất kỳ loại dự án Node nào, cho dù đó là thư viện, công cụ dòng lệnh hay thậm chí là trang web. Bằng cách sử dụng các tùy chọn và plugin khác nhau có sẵn, bạn sẽ có thể đáp ứng nhu cầu thử nghiệm của mình khá dễ dàng. Mỗi thư viện này đều rất hữu ích để xác thực mã của bạn và chỉ nên được sử dụng trong tất cả các dự án Node của bạn.

Hy vọng rằng đây là phần giới thiệu hữu ích về Mocha và Chai. Có rất nhiều điều cần tìm hiểu hơn những gì tôi đã trình bày ở đây, vì vậy hãy nhớ xem tài liệu để biết thêm thông tin.

Dấu thời gian:

Thêm từ xếp chồng lên nhau