tham gia các bài kiểm tra từ nhiều tệp với mocha.js


87

Tôi đang cố gắng kết hợp tất cả các bài kiểm tra từ nhiều tệp trong một tệp, giống như sau:

  describe('Controllers', function() {
    describe('messages.js', function() {
      require('./controllertests/messages').test(options);
    })
    describe('users.js', function() {
      require('./controllertests/users').test(options);
    })
  })

Tôi khá chắc rằng đây không phải là cách tốt nhất để tham gia các bài kiểm tra, tôi đang gặp một số khó khăn trong việc tìm kiếm các ví dụ về cách thực hiện điều này: s


1
Tò mò, tại sao các bài kiểm tra cần được kết hợp với nhau trong một tệp?
thgaskell

2
Để chia sẻ các biến địa phương và tổ chức
coiso

Sẽ có ý nghĩa hơn nếu bạn đưa các bài kiểm tra vào câu hỏi. Có vẻ như bạn có thể nghiêng về các bài kiểm tra tích hợp (trái ngược với các bài kiểm tra đơn vị). Nói chung, bạn không cần phải chia sẻ các biến trong các thử nghiệm.
thgaskell

2
Và vấn đề lớn là tôi muốn có như 20 file hơn tập 1 huuuuge
coiso

2
Ngoài ra, nếu bạn nhìn vào cách Mocha xử lý các bộ với khái niệm về .only()nó có thể hữu ích khi có thể describe.only()chạy toàn bộ thư mục thử nghiệm. Đó là những gì đã đưa tôi đến đây.
Chris

Câu trả lời:


113

Nếu bạn muốn bao gồm nhiều mô-đun vào bạn describephân cấp như bạn đang làm trong câu hỏi của bạn, những gì bạn đang làm là khá nhiều , trừ khi bạn muốn viết một bộ nạp kiểm tra tùy chỉnh cho Mocha. Viết trình tải tùy chỉnh sẽ không dễ dàng hơn hoặc làm cho mã của bạn rõ ràng hơn những gì bạn đã có.

Đây là một ví dụ về cách tôi sẽ thay đổi một vài thứ. Thư testmục con trong ví dụ này được tổ chức như sau:

.
└── test
    ├── a
    │   └── a.js
    ├── b
    │   └── b.js
    ├── common.js
    └── top.js

top.js:

function importTest(name, path) {
    describe(name, function () {
        require(path);
    });
}

var common = require("./common");

describe("top", function () {
    beforeEach(function () {
       console.log("running something before each test");
    });
    importTest("a", './a/a');
    importTest("b", './b/b');
    after(function () {
        console.log("after all tests");
    });
});

Các importTestchức năng là chỉ để cho thấy làm thế nào nó sẽ có thể để xử lý sự lặp lại của nhập khẩu nhiều mô-đun mà không cần phải gõ lại toàn bộ describe(... require...điều mỗi lần duy nhất. Các commonmô-đun có nghĩa là để giữ những gì bạn cần để sử dụng trong nhiều mô-đun của bộ ứng dụng thử nghiệm. Tôi không thực sự sử dụng nó trong topnhưng nó có thể được sử dụng ở đó, nếu cần.

Tôi sẽ lưu ý ở đây rằng beforeEachsẽ chạy mã của nó trước mỗi và mọi thử nghiệm đơn lẻ được đăng ký với itviệc chúng xuất hiện bên describetrong tophoặc chúng xuất hiện trong bất kỳ mô-đun nào được nhập . Với --recursive, beforeEachmã sẽ phải được sao chép vào từng mô-đun hoặc có lẽ bạn sẽ có một beforeEachhook trong mỗi mô-đun gọi một hàm được nhập từ một mô-đun chung.

Ngoài ra, afterhook sẽ chạy sau tất cả các thử nghiệm trong bộ. Điều này không thể được lặp lại với --recursive. Nếu bạn sử dụng --recursivevà thêm mã của aftermỗi mô-đun, nó sẽ được thực thi một lần cho mỗi mô-đun thay vì chỉ một lần cho toàn bộ bài kiểm tra.

Việc có tất cả các bài kiểm tra xuất hiện dưới một toptiêu đề duy nhất không thể được sao chép bằng cách sử dụng --recursive. Với --recursivemỗi tệp có thể có describe("top"nhưng điều này sẽ tạo ra một toptiêu đề mới cho mỗi tệp.

common.js:

var chai = require("chai");

var options = {
    foo: "foo"
};

exports.options = options;
exports.chai = chai;
exports.assert = chai.assert;

Sử dụng một mô-đun có tên commonnhư thế này là điều tôi đã làm trong một số bộ thử nghiệm của mình để tránh phải requirelặp đi lặp lại nhiều thứ và giữ các biến hoặc hàm chỉ đọc toàn cục không giữ trạng thái. Tôi không muốn làm ô nhiễm globalđối tượng như trong câu trả lời của thgaskell vì đối tượng này thực sự là toàn cầu và có thể truy cập được ngay cả trong các thư viện của bên thứ ba mà mã của bạn có thể đang tải. Đây không phải là điều tôi thấy có thể chấp nhận được trong mã của mình.

a/a.js:

var common = require("../common");
var options = common.options;
var assert = common.assert;

it("blah a", function () {
    console.log(options.foo);
    assert.isTrue(false);
});

b/b.js:

it("blah b", function () {});

3
Mặc dù tôi đồng ý rằng bạn không nên làm ô nhiễm globalphạm vi, nhưng tôi sử dụng điều này cho các thư viện xác nhận để giữ cho các tệp kiểm tra sạch hơn. Nó không giống như bạn đang ghi đè global.process. Các biến cục bộ sẽ ghi đè globaltrừ khi các thư viện khác đang gọi một cách rõ ràng global.XYZ, điều này khó xảy ra. Nó chỉ kéo dài trong thời gian của các bài kiểm tra. Đã không làm tổn thương tôi, nhưng tôi sẽ cho bạn biết thời điểm nó cắn tôi trong ass :)
thgaskell

Sự khác biệt giữa importTestvà gọi require('path')()ví dụ là gì?
CherryNerd

@CreasolDev importTestChức năng này chỉ là một chức năng tiện lợi. Điều quan trọng nó làm là gói requirecuộc gọi trong một describekhối. Điều quan trọng là requirecuộc gọi phải được bao bọc trong describenếu không các mô-đun sẽ không bị tách biệt trong khối riêng của chúng và bất kỳ hook nào được đặt bởi tệp đã nhập sẽ được đặt trên khối sai. Nếu importTestđược thay thế bằng một cuộc gọi trực tiếp đến requiremà không có gói describe, thì các mô-đun a/ab/bsẽ chia sẻ các hook. Ví dụ, một beforeEachhook được đặt trong b/bcũng sẽ chạy trước mỗi lần kiểm tra trong a/a.
Louis

1
Tôi sẽ KHÔNG chạy bất kỳ logic nào như trước đây Mỗi trong mô tả cấp cao nhất của bạn. Hãy để mỗi tệp tự làm trước Mỗi "thứ". Bạn sẽ ghép các bài kiểm tra của mình với nhau và việc triển khai không liên quan nếu bạn làm điều này.
Tích

1
Tôi cũng sẽ thực hiện gói các mô tả trong các tệp tương ứng của chúng, không phải trong hàm importTest. Cấp cao nhất mô tả trong mỗi tập tin tương ứng nên được mô tả mục đích dãy phòng thử nghiệm của họ anyway
PositiveGuy

35

Mặc dù điều này có thể không liên quan trực tiếp đến câu hỏi, nhưng câu trả lời tôi đang tìm kiếm là:

$ mocha --recursive

Sẽ thực hiện tất cả các thử nghiệm trong các thư mục con của thư mục "thử nghiệm". Khéo léo. Tiết kiệm việc phải duy trì danh sách các bài kiểm tra mà tôi muốn tải và thực sự chỉ luôn chạy mọi thứ.


3
Câu trả lời tốt nhất! Đơn giản hơn nhiều so với các giải pháp đề xuất khác.
caiosm1005 28-07-16

12
@ caiosm1005 Câu trả lời này không thực sự giải quyết được vấn đề mà OP trình bày . Chắc chắn, nếu bạn không cần làm những gì OP muốn làm , thì bạn nên sử dụng cái này. Tuy nhiên, nếu bạn muốn gói mỗi tệp thử nghiệm thành nhiều describekhối, thì describecác khối kéo dài các tệp --recursivesẽ không làm được. Vì nó không giải quyết được vấn đề của OP, tôi sẽ không gọi nó là "tốt nhất".
Louis

@louis - Tôi tin rằng bạn có thể quấn mỗi tập tin riêng biệt trong describekhối
Ian Jamieson

4
@IanJamieson OP đang cố gắng có nhiều tệp được bao phủ bởi một khối duy nhất describe . Nhìn vào câu hỏi. Khối "Bộ điều khiển" describephải bao gồm các thử nghiệm của ./controllertests/messages.js./controllertests/users.js. Đập --recursivevào một lời gọi Mocha không tạo ra một describe("Controllers"khối một cách kỳ diệu .
Louis

3
@Louis Chỉ đang cố gắng giúp đỡ. Xin lỗi nếu tôi đã xúc phạm bạn bằng cách cố gắng tạo ra describecác khối - điều mà tôi thực sự đã học được từ chính cụ Dumbledore.
Ian Jamieson

16

Không có gì ngăn cản bạn chạy nhiều tệp thử nghiệm. Nói chung, mỗi thử nghiệm không nên phụ thuộc vào kết quả của một thử nghiệm khác, vì vậy việc chia sẻ các biến không phải là điều bạn muốn làm.

Đây là một ví dụ về cách bạn có thể tổ chức các tệp thử nghiệm của mình.

.
├── app.js
└── test
    ├── common.js
    ├── mocha.opts
    │
    ├── controllers
    │   ├── messages-controller.js
    │   └── users-controller.js
    │
    └── models
        ├── messages-model.js
        └── users-model.js

Sau đó, bên trong mocha.optstệp của bạn , hãy đảm bảo đặt --recursivetùy chọn.

mocha.opts

--ui bdd
--recursive

Nếu có module phổ biến mà bạn muốn bao gồm trong tất cả các file, bạn có thể bổ sung vào common.jstập tin. Các tệp ở thư mục gốc testsẽ chạy trước các tệp trong thư mục lồng nhau.

common.js

global.chai = require('chai');
global.assert = chai.assert;
global.expect = chai.expect;
chai.should();
chai.config.includeStack = true;

process.env.NODE_ENV = 'test';

// Include common modules from your application that will be used among multiple test suites.
global.myModule = require('../app/myModule');

3
Có ai phiền thêm mã cho các tệp trong thư mục bộ điều khiển và mô hình không? Sẽ rất tuyệt nếu có một ví dụ đầy đủ.
Gavin

@Gavin - đây chỉ là những bộ quần áo thử nghiệm nên chúng sẽ chứadescribe('mytest', function() { /* ..... etc */ });
Ian Jamieson

8

Tôi biết đây là một bài viết cũ nhưng tôi muốn làm quen với những gì đã là một giải pháp tốt đối với tôi, rất giống với phương pháp mà OP đề xuất.

Dự án tôi đang làm đã được thử nghiệm tốt và các thử nghiệm tiếp tục phát triển. Tôi đã kết thúc việc sử dụng requirevì nó đồng bộ và do đó làm cho việc soạn các bài kiểm tra của bạn dễ dàng hơn một chút mà không có quá nhiều thay đổi về kiến ​​trúc:

// inside test/index.js

describe('V1 ROUTES', () => {
  require('./controllers/claims.test');
  require('./controllers/claimDocuments.test');
  require('./controllers/claimPhotos.test');
  require('./controllers/inspections.test');
  require('./controllers/inspectionPhotos.test');
  require('./controllers/versions.test');
  require('./services/login.v1.test');
});

describe('V2 ROUTES', () => {
  require('./services/login.v2.test');
  require('./services/dec-image.v2.test');
});

describe('V3 ROUTES', () => {
  require('./services/login.v3.test');
  require('./services/getInspectionPhotosv3.test');
  require('./services/getPolicyInfo.v3.test');
});

describe('ACTIONS', () => {
  require('./actions/notifications.test');
});

2

Tôi đã gặp vấn đề tương tự khi tôi có nhiều bài kiểm tra cho các lớp trong cùng một danh mục và tôi muốn nhóm chúng lại với nhau để giúp xem chúng trong IDE dễ dàng hơn. Tất cả các bài kiểm tra và mã của tôi đều đã sử dụng các mô-đun ES6 - tôi không muốn viết lại tất cả chúng để sử dụng requirenhư tôi đã thấy trong các ví dụ khác.

Tôi đã giải quyết nó bằng cách describexuất "nhóm" của mình , sau đó nhập nó vào các tệp thử nghiệm của tôi và thêm chúng vào mục đã nhập theo chương trình describe. Tôi đã kết thúc việc tạo một phương thức trợ giúp để loại bỏ tất cả các hệ thống ống nước.

Trong someCategory.spec.js

const someCategory= describe("someCategory", () => {});


// Use this just like a regular `describe` to create a child of this scope in another file
export default function describeMember(skillName, testFn) {
  return describe(skillName, function configureContext() {
    // Make context a child of `someCategory` context
    function Context() {}
    Context.prototype = someCategory.ctx;
    this.ctx = new Context();
    // Re-parent the suite created by `describe` above (defaults to root scope of file it was created in)
    this.parent.suites.pop();
    someCategory.addSuite(this);
    // Invoke the fn now that we've properly set up the parent/context
    testFn.call(this);
  });
}

Trong các bài kiểm tra cá nhân:

import { default as describeCategoryMember } from './someCategory.spec';

describeCategoryMember('something', () => {
    describe('somethingElse', () => {
        ...
    });

    it('a test', () => {
        ...
    });
})

-11
describe( 'Running automation test, Please wait for all test to complete!'.red, function () {


    var run = require( './Test.js' );

    for ( var i = 0; i < 2; i++ ) {
        run.badLogin();
        run.loginLimited();
        run.acceptJob();
        run.drivingToJob();
        run.arrivedAtJob();
        run.towingJob();
        run.arrivedDestination();
        run.jobComplete();
        run.restrictionLicensePlate();
        run.newNodeMainMenu();
        run.newNodeMainMenuToDrafts();
        run.draftDelete();
        run.resetAllData();
        run.companyVehicle();
        run.actionsScreenClockInOut();
        run.mainMenuLogout();
        run.loginAdmin();
        run.actionsScreenLogout();
    }
} );

3
Tốt nhất là thêm mô tả cùng với mã để những người khác có thể xác định xem đây có phải là câu trả lời chấp nhận được hay không.
Suever

2
Tại sao vòng lặp? Có gì trong ./Test.js? Ai biết? Về kỷ lục, tôi hiện là người trả lời nhiều nhất trong thẻ mocha . Tôi biết Mocha từ trong ra ngoài nhưng tôi không thể hiểu được câu trả lời này.
Louis

@Louis có vẻ như anh ấy muốn chạy thử nghiệm n lần bằng cách sử dụng vòng lặp.
Akash Agarwal
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.