mocha.js ile birden fazla dosyadan testlere katılma


88

Birden fazla dosyadaki tüm testleri tek bir dosyada birleştirmeye çalışıyorum, bunun gibi bir şey:

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

Testlere katılmanın en iyi yolu olmadığından oldukça eminim, bunun nasıl yapılacağına dair bazı örnekler bulmakta güçlük çekiyorum:


1
Merak ediyorum, testlerin neden tek bir dosyada birleştirilmesi gerekiyor?
thgaskell

2
Yerel değişkenleri ve organizasyonu paylaşmak için
coiso

Testleri soruya dahil etmeniz daha mantıklı olabilir. Görünüşe göre entegrasyon testlerine yöneliyorsunuz (birim testlerinin aksine). Genel olarak, değişkenleri testler arasında paylaşmanıza gerek yoktur.
thgaskell

2
Ve en büyük sorun, 1 huuuge dosyasından daha 20 dosyaya sahip olmayı tercih etmemdir
coiso

2
Ayrıca, Mocha'nın süitleri konseptiyle nasıl ele aldığına bakarsanız, yine de bütün bir test dizini çalıştırabilmeniz .only()yararlı olabilir describe.only(). Beni buraya getiren buydu.
Chris

Yanıtlar:


114

Birden modülleri eklemek istiyorsanız içine senin describesenin soru yapıyorsun gibi hiyerarşi, ne yapıyorsun oldukça fazla olduğunu o size Mocha için özel bir test yükleyici yazmak istemiyorsan. Özel yükleyiciyi yazmak daha kolay olmaz veya kodunuzu sahip olduğunuzdan daha net hale getirmez.

İşte birkaç şeyi nasıl değiştirebileceğime dair bir örnek. testBu örnekte, alt-klasör şekilde düzenlenmiştir:

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

importTestFonksiyon sadece bütün yeniden yazmak zorunda kalmadan birden fazla modülleri ithal tekrarını işlemek mümkün olacağını nasıl göstermek için describe(... require...şeyi her seferinde. commonModül test paketi birden modüllerde kullanmak için gerekenleri barındırma anlamına gelir. Aslında içinde kullanmıyorum topama gerekirse orada kullanılabilir.

Burada, beforeEachkaydedilen her bir testten önce it, içeriğin describeiçinde mi topyoksa içe aktarılan modüllerin herhangi birinde mi göründükleriyle birlikte kodunu çalıştıracağını not edeceğim . İle --recursive, beforeEachkodun her modüle kopyalanması gerekir veya belki de beforeEachher modülde ortak bir modülden içe aktarılan bir işlevi çağıran bir kancanız olur.

Ayrıca, afterçengel süitteki tüm testlerden sonra çalışacaktır . Bu, ile çoğaltılamaz --recursive. Her modüle --recursivekodunu kullanır ve eklerseniz after, tüm test için yalnızca bir kez yerine modül başına bir kez çalıştırılır .

Tüm testlerin tek bir topbaşlık altında görünmesi kullanılarak çoğaltılamaz --recursive. İle --recursiveher dosya olabilir describe("top"ama bu yeni yaratacak topher dosya için başlık.

common.js:

var chai = require("chai");

var options = {
    foo: "foo"
};

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

Bu şekilde adlandırılmış bir modül kullanmak common, bazı test takımlarımda requiredefalarca bir sürü şeyden kaçınmak ve durumu tutmayan küresel salt okunur değişkenleri veya işlevleri tutmak için yaptığım bir şey. globalNesneyi thgaskell'in cevabında olduğu gibi kirletmemeyi tercih ederim çünkü bu nesne gerçekten geneldir ve kodunuzun yüklediği üçüncü şahıs kitaplıklarında bile erişilebilirdir. Bu benim kodumda kabul edilebilir bulduğum bir şey değil.

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
globalKapsamı kirletmemeniz gerektiğini kabul etsem de , bunu test dosyalarını daha temiz tutmak için iddia kitaplıkları için kullanıyorum. Üzerine yazdığınız gibi değil global.process. globalDiğer kitaplıklar açıkça çağırmadığı sürece yerel değişkenler geçersiz global.XYZkılınacaktır. Sadece testler süresince sürer. Henüz beni incitmedi, ama beni kıçımdan ısırdığı an size haber vereceğim :)
thgaskell

Örneğin, importTestaramak ve aramak arasındaki fark nedir require('path')()?
CherryNerd

@CreasolDev importTestFonksiyon sadece bir kolaylık fonksiyonudur. Yaptığı önemli şey requirearamayı bir describebloğa sarmaktır. requireÇağrının sarmalanması önemlidir, describeaksi takdirde modüller kendi bloklarında izole edilmeyecek ve içe aktarılan dosya tarafından ayarlanan herhangi bir kanca yanlış blokta ayarlanacaktır. Eğer importTestdoğrudan bir çağrı ile değiştirildi requirebir sarma olmadan describe, sonra modülleri a/ave b/bkancalar paylaşmak istiyorum. Örneğin, bir beforeEachkanca seti b/bde her testten önce çalışır a/a.
Louis

1
Daha önce olduğu gibi herhangi bir mantığı çalıştırmazdım, üst seviyenizdeki her biri açıklar. Bırakın her dosya, her "şeyden" önce kendi işini yapsın. Bunu yaparsanız, testlerinizi birbiriyle ve ilgisiz uygulama ile birleştiriyor olacaksınız.
PositiveGuy

1
Ayrıca, importTest işlevinde değil, ilgili dosyalarında tanımların sarmalanmasını da yapardım. Her bir dosyadaki en üst seviye, test takımlarının amacını açıklıyor olmalıdır
PositiveGuy

35

Bu soruyla doğrudan bağlantılı olmasa da aradığım cevap şuydu:

$ mocha --recursive

"Test" klasörünün alt dizinlerinde bulunan tüm testleri yürütecektir. Düzgün. Yüklemek istediğim ve aslında her zaman her şeyi çalıştırdığım testlerin bir listesini tutmaktan tasarruf ediyor.


3
En iyi cevap! Önerilen diğer çözümlerden çok daha basit.
caiosm1005

12
@ caiosm1005 Bu cevap aslında OP tarafından sunulan problemi çözmüyor . Elbette, OP'nin yapmak istediği şeyi yapmanız gerekmiyorsa, bunu kullanmalısınız. Ancak, her bir test dosyasını birden çok describebloğa sarmak istiyorsanız , describedosyaları kapsayan bloklar --recursivebunu yapmaz. OP'nin problemini çözmediğini görsem, buna "en iyi" demezdim.
Louis

@louis - Her bir dosyayı describebloklar halinde paketleyebileceğinize inanıyorum
Ian Jamieson

4
@IanJamieson OP, tek bir blok tarafından kapsanan birden fazla dosyayı almaya çalışıyor . Soruya bakın. "Kontrolörler" blok testleri kapsaması gerektiğini ve . Bir Mocha çağrısına vurmak sihirli bir şekilde bir blok oluşturmaz . describedescribe./controllertests/messages.js./controllertests/users.js--recursivedescribe("Controllers"
Louis

3
@Louis Sadece yardım etmeye çalışıyorum. Sihirli bir şekilde describebloklar yaratmaya çalışarak sizi rahatsız ettiysem özür dilerim - bunu aslında Dumbledore'un kendisinden öğrendim.
Ian Jamieson

16

Birden fazla test dosyası çalıştırmanızı engelleyen hiçbir şey yoktur. Genel olarak, her test başka bir testin sonuçlarına bağlı olmamalıdır, bu nedenle değişkenleri paylaşmak, yapmak isteyeceğiniz bir şey değildir.

İşte test dosyalarınızı nasıl düzenleyebileceğinize dair bir örnek.

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

Ardından mocha.optsdosyanızın içinde --recursiveseçeneği ayarladığınızdan emin olun .

mocha.opts

--ui bdd
--recursive

Orada ise şunlardır tüm dosyalar arasında yer almasını istediğiniz ortak modüller, sen o ekleyebilir common.jsdosyası. testDizinin kök dizinindeki dosyalar, iç içe dizinlerdeki dosyalardan önce çalışacaktır.

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
Denetleyicilere ve model dizinlerine dosyalar için kod eklemenin sakıncası var mı? Tam bir örnek olması harika olurdu.
Gavin

@Gavin - bunlar sadece test kıyafetleri olacak, böylece içereceklerdescribe('mytest', function() { /* ..... etc */ });
Ian Jamieson

8

Bunun eski bir gönderi olduğunu biliyorum, ancak OP'nin önerdiği yönteme çok benzeyen, benim için iyi bir çözüm olan neyin var olduğunu söylemek istedim.

Üzerinde çalıştığım proje iyi test edildi ve testler büyümeye devam ediyor. Kullanmayı bıraktım requireçünkü eşzamanlı ve bu nedenle mimaride çok fazla değişiklik yapmadan testlerinizi oluşturmayı biraz kolaylaştırıyor:

// 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

Aynı kategorideki sınıflar için bir dizi testin olduğu benzer bir sorun yaşadım ve onları bir IDE'de görüntülemeyi kolaylaştırmak için bir arada gruplamak istedim. Tüm testlerim ve kodum zaten ES6 modüllerini kullanıyordu - hepsini requirediğer örneklerde gördüğüm gibi kullanmak için yeniden yazmak istemedim .

"Gruplamamın" describedışa aktarılmasını ve ardından test dosyalarıma aktararak ve bunları programlı olarak içe aktarılan dosyaya ekleyerek çözdüm describe. Sonunda tüm sıhhi tesisattan kurtulmak için yardımcı bir yöntem yarattım.

SomeCategory.spec.js içinde

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

Bireysel testlerde:

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
Başkalarının bunun kabul edilebilir bir cevap olup olmadığını belirleyebilmesi için kodla birlikte bir açıklama eklemek en iyisidir.
Suever

2
Neden döngü? İçinde ne var ./Test.js? Kim bilir? Kayıt için, şu anda mocha etiketinde en çok cevap veren kişi benim . Mocha'yı içten dışa biliyorum ama bu cevabı anlamıyorum.
Louis

@Louis , döngüyü kullanarak testleri n kez çalıştırmak istiyor gibi görünüyor .
Akash Agarwal
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.