menggabungkan tes dari beberapa file dengan mocha.js

88

Saya mencoba untuk menggabungkan semua tes dari beberapa file dalam satu file, seperti ini:

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

Saya cukup yakin ini bukan cara terbaik untuk mengikuti tes, saya kesulitan menemukan contoh bagaimana melakukan ini: s

coiso
sumber
1
Penasaran, kenapa tes-tes tersebut perlu digabungkan menjadi satu file?
thgaskell
2
Untuk berbagi variabel dan organisasi lokal
coiso
Mungkin lebih masuk akal jika Anda memasukkan tes ke dalam pertanyaan. Sepertinya Anda cenderung memilih pengujian integrasi (bukan pengujian unit). Umumnya Anda tidak perlu membagikan variabel di seluruh pengujian.
thgaskell
2
Dan masalah besarnya adalah saya lebih suka memiliki 20 file daripada 1 file besar
coiso
2
Selain itu, jika Anda melihat bagaimana Mocha menangani suite dengan konsepnya .only(), mungkin berguna describe.only()untuk tetap menjalankan seluruh direktori pengujian. Itulah yang membawaku ke sini.
Chris

Jawaban:

114

Jika Anda ingin menyertakan beberapa modul ke dalam Anda describehierarki seperti yang Anda lakukan dalam pertanyaan Anda, apa yang Anda lakukan adalah cukup banyak itu , kecuali jika Anda ingin menulis tes kustom loader untuk Mocha. Menulis pemuat khusus tidak akan lebih mudah atau membuat kode Anda lebih jelas daripada yang sudah Anda miliki.

Berikut adalah contoh bagaimana saya mengubah beberapa hal. The testsubdirektori dalam contoh ini disusun sebagai:

.
└── 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");
    });
});

The importTestfungsi hanya untuk menunjukkan bagaimana itu akan mungkin untuk menangani pengulangan mengimpor beberapa modul tanpa mengetik ulang seluruh describe(... require...hal setiap saat. The commonModul ini dimaksudkan untuk menahan apa yang Anda butuhkan untuk digunakan dalam beberapa modul dari test suite. Sebenarnya saya tidak menggunakannya toptetapi bisa digunakan di sana, jika perlu.

Saya akan mencatat di sini bahwa beforeEachakan menjalankan kodenya sebelum masing-masing dan setiap tes terdaftar dengan itapakah mereka muncul di describedalam topatau mereka muncul di salah satu modul yang diimpor . Dengan --recursive, beforeEachkode harus disalin ke setiap modul atau mungkin Anda akan memiliki beforeEachkaitan di setiap modul yang memanggil fungsi yang diimpor dari modul umum.

Juga, afterpengait akan berjalan setelah semua pengujian di suite. Ini tidak dapat direplikasi dengan --recursive. Jika Anda menggunakan --recursivedan menambahkan kode afterke setiap modul, ini akan dijalankan satu kali per modul, bukan hanya sekali untuk keseluruhan pengujian.

Memiliki semua tes yang muncul di bawah satu topjudul tidak dapat direplikasi dengan menggunakan --recursive. Dengan --recursivesetiap file bisa saja describe("top"tapi ini akan membuat topheading baru untuk tiap file.

common.js:

var chai = require("chai");

var options = {
    foo: "foo"
};

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

Menggunakan modul bernama commonseperti ini adalah sesuatu yang telah saya lakukan di beberapa rangkaian pengujian saya untuk menghindari keharusan untuk requirebanyak hal berulang-ulang dan untuk menahan variabel atau fungsi hanya-baca global yang tidak menjaga status. Saya memilih untuk tidak mencemari globalobjek seperti dalam jawaban thgaskell karena objek ini benar-benar global dan dapat diakses bahkan di pustaka pihak ketiga yang mungkin memuat kode Anda. Ini bukanlah sesuatu yang menurut saya dapat diterima dalam kode saya.

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 () {});
Louis
sumber
3
Meskipun saya setuju bahwa Anda tidak boleh mencemari globalcakupan, saya menggunakan ini untuk pustaka pernyataan agar file pengujian tetap bersih. Ini tidak seperti Anda menimpa global.process. Variabel lokal akan diganti globalkecuali pustaka lain secara eksplisit memanggil global.XYZyang tidak mungkin. Itu hanya berlangsung selama tes. Belum menyakiti saya, tapi saya akan memberi tahu Anda saat itu menggigit saya di pantat :)
thgaskell
Apa perbedaan antara importTestdan menelepon require('path')()misalnya?
CherryNerd
@CreasolDev importTestFungsinya hanyalah fungsi kenyamanan. Hal penting yang dilakukannya adalah membungkus requirepanggilan dalam satu describeblok. Penting agar requirepanggilan dibungkus describejika tidak modul tidak akan diisolasi di blok mereka sendiri dan setiap kait yang ditetapkan oleh file yang diimpor akan disetel pada blok yang salah. Jika importTestdiganti dengan panggilan langsung ke requiretanpa pembungkus describe, maka modul a/adan b/bkait akan berbagi. Misalnya, beforeEachset hook b/bjuga akan berjalan sebelum setiap pengujian masuk a/a.
Louis
1
Saya TIDAK akan menjalankan logika apa pun seperti beforeEach di tingkat atas Anda menjelaskan. Biarkan setiap file melakukan "barang" sendiri beforeEach. Anda akan menggabungkan pengujian Anda satu sama lain dan implementasi yang tidak terkait jika Anda melakukan ini.
PositiveGuy
1
Saya juga akan melakukan pembungkus menjelaskan di file masing-masing, bukan di fungsi importTest. Tingkat atas menjelaskan dalam setiap file masing-masing harus menjelaskan tujuan suite pengujian mereka
PositiveGuy
35

Meskipun ini mungkin tidak terkait langsung dengan pertanyaan, jawaban yang saya cari adalah:

$ mocha --recursive

Akan menjalankan semua tes dalam sub direktori dari folder "test". Rapi. Menghemat keharusan memelihara daftar tes yang ingin saya muat dan sebenarnya selalu menjalankan semuanya.

Ian Jamieson
sumber
3
Jawaban Terbaik! Jauh lebih sederhana dari solusi lain yang diusulkan.
caiosm1005
12
@ caiosm1005 Jawaban ini sebenarnya tidak memecahkan masalah yang disajikan oleh OP . Tentu, jika Anda tidak perlu melakukan apa yang OP ingin lakukan , maka Anda harus menggunakan ini. Namun, jika Anda ingin membungkus setiap file pengujian dalam beberapa describeblok, describeblok yang menjangkau file, --recursivetidak akan melakukannya. Karena tidak menyelesaikan masalah OP, saya tidak akan menyebutnya "terbaik".
Louis
@louis - Saya yakin Anda dapat membungkus setiap file terpisah dalam describeblok
Ian Jamieson
4
@IanJamieson OP mencoba untuk memiliki beberapa file yang dicakup oleh satu describe blok. Lihat pertanyaannya. describeBlok "Pengontrol" harus mencakup pengujian ./controllertests/messages.jsdan ./controllertests/users.js. Menampar --recursivedoa Mocha tidak secara ajaib membuat describe("Controllers"blok.
Louis
3
@Louis Hanya mencoba membantu. Maaf jika saya menyinggung Anda dengan mencoba membuat describebalok secara ajaib - yang sebenarnya saya pelajari dari Dumbledore sendiri.
Ian Jamieson
16

Tidak ada yang mencegah Anda menjalankan beberapa file uji. Umumnya, setiap pengujian tidak boleh bergantung pada hasil pengujian lain, jadi berbagi variabel bukanlah sesuatu yang ingin Anda lakukan.

Berikut adalah contoh bagaimana Anda dapat mengatur file pengujian Anda.

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

Kemudian di dalam mocha.optsfile Anda , pastikan untuk mengatur --recursiveopsi.

mocha.opts

--ui bdd
--recursive

Jika ada yang modul umum bahwa Anda ingin memasukkan seluruh file, Anda dapat menambahkan bahwa ke common.jsberkas. File di root testdirektori akan berjalan sebelum file di direktori bersarang.

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');
thgaskell
sumber
3
Adakah yang keberatan menambahkan kode untuk file di direktori controller dan model? Akan sangat bagus untuk memiliki contoh lengkap.
Gavin
@Gavin - ini hanya akan menjadi uji jas sehingga akan berisidescribe('mytest', function() { /* ..... etc */ });
Ian Jamieson
8

Saya tahu ini adalah posting lama tetapi saya ingin berpadu dengan apa yang telah menjadi solusi yang baik bagi saya, sangat mirip dengan metode yang diusulkan oleh OP.

Proyek yang saya kerjakan telah diuji dengan baik dan pengujiannya terus berkembang. Saya akhirnya menggunakan requirekarena sinkron dan karenanya membuatnya sedikit lebih mudah untuk menyusun pengujian Anda tanpa terlalu banyak perubahan dalam arsitektur:

// 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');
});
Mike Fleming
sumber
2

Saya memiliki masalah serupa di mana saya memiliki banyak tes untuk kelas dalam kategori yang sama dan saya ingin mengelompokkannya bersama-sama untuk membuatnya lebih mudah dilihat dalam IDE. Semua tes dan kode saya sudah menggunakan modul ES6 - saya tidak ingin menulis ulang semuanya untuk digunakan requireseperti yang saya lihat di contoh lain.

Saya menyelesaikannya dengan describemengekspor "pengelompokan" saya , lalu mengimpornya ke file pengujian saya dan secara terprogram menambahkannya ke yang diimpor describe. Saya akhirnya membuat metode pembantu untuk memisahkan semua pipa ledeng.

Di 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);
  });
}

Dalam tes individu:

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

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

    it('a test', () => {
        ...
    });
})
Jon Senchyna
sumber
-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();
    }
} );
Mike
sumber
3
Yang terbaik adalah menambahkan deskripsi bersama dengan kode sehingga orang lain dapat menentukan apakah ini jawaban yang dapat diterima.
Suever
2
Mengapa loop? Ada apa ./Test.js? Siapa tahu? Sebagai catatan, saat ini saya adalah penjawab pertanyaan teratas di tag moka . Saya tahu Mocha luar dalam tetapi saya tidak bisa memahami jawaban ini.
Louis
@Louis sepertinya dia ingin menjalankan tes n kali menggunakan loop.
Akash Agarwal