2015-09-03 4 views
9

Ich bin auf der Suche nach einer Möglichkeit, Async-Code vor dem gesamten Mocha-Test auszuführen.Ausführen von Async-Code vor dem vollständigen Mocha-Test

Hier ist ein Beispiel für einen Test, der ein Array von Argumenten & Erwartungen und Schleifen über alle Elemente in diesem Array verwendet, um Funktionserklärungen zu erzeugen.

var assert = require('assert') 

/* global describe, it*/ 

var fn = function (value) { 
    return value + ' ' + 'pancake' 
} 

var tests = [ 
    { 
    'arg': 'kitty', 
    'expect': 'kitty pancake' 
    }, 
    { 
    'arg': 'doggy', 
    'expect': 'doggy pancake' 
    }, 
] 

describe('example', function() { 
    tests.forEach(function (test) { 
    it('should return ' + test.expect, function(){ 
     var value = fn(test.arg) 
     assert.equal(value, test.expect) 
    }) 
    }) 
}) 

Nun, meine Frage ist, wie würde diese Arbeit, wenn die Tests Wert von einem Versprechen kam, wie folgt aus:

var assert = require('assert') 
var Promise = require('bluebird') 

/* global describe, it*/ 

var fn = function (value) { 
    return value + ' ' + 'pancake' 
} 

function getTests() { 
    return Promise.resolve('kitty pancake') 
    .delay(500) 
    .then(function (value) { 
    return [ 
     { 
     'arg': 'kitty', 
     'expect': value 
     }, 
     { 
     'arg': 'doggy', 
     'expect': 'doggy pancake' 
     } 
    ] 
    }) 
} 

getTests().then(function (tests) { 
    describe('example', function() { 
    tests.forEach(function (test) { 
     it('should return ' + test.expect, function(){ 
     var value = fn(test.arg) 
     assert.equal(value, test.expect) 
     }) 
    }) 
    }) 
}) 

auch versucht:

describe('example', function() { 
    getTests().then(function (tests) { 
    tests.forEach(function (test) { 
     it('should return ' + test.expect, function(){ 
     var value = fn(test.arg) 
     assert.equal(value, test.expect) 
     }) 
    }) 
    }) 
}) 

jedoch in diesem Beispiel keine Die Tests laufen, weil Mocha die Anweisung describe nicht erkennt, weil sie sich innerhalb eines Versprechens befindet.

before/beforeEach werden nichts tun sowieso mit einem Test im Format zu helfen, es sei denn, der ein beforeTest Haken war, dass Mokka mit dem Wissen liefern würde, dass ein Asynchron-Betrieb gibt es die vor dem gesamten Test ausgeführt werden muss.

Antwort

1

Ich bin nicht sicher, ob es eine einfache Möglichkeit gibt, dies zu tun, aber Sie könnten versuchen, run Mocha programatically.

Hier ist eine kleine schmutzige Version von wie das aussehen könnte, nur um die Idee zu zeigen.

data.js

var Promise = require('bluebird') 

module.exports.tests = [] 

function getTests() { 
    return Promise.resolve('kitty pancake') 
    .delay(500) 
    .then(function (value) { 
    module.exports.tests = [ 
     { 
     'arg': 'kitty', 
     'expect': value 
     }, 
     { 
     'arg': 'doggy', 
     'expect': 'doggy pancake' 
     } 
    ] 
    }) 
} 

module.exports.getTests = getTests 

test-launcher.js

var Mocha = require('mocha'), 
    fs = require('fs'), 
    path = require('path') 

// First, you need to instantiate a Mocha instance. 
var mocha = new Mocha() 

// Then, you need to use the method "addFile" on the mocha 
// object for each file. 

// Here is an example: 
fs.readdirSync('test').filter(function(file){ 
    // Only keep the .js files 
    return file.substr(-3) === '.js' 

}).forEach(function(file){ 
    // Use the method "addFile" to add the file to mocha 
    mocha.addFile(
     path.join('test', file) 
    ) 
}) 

// make sure your tests are loaded before running the tests 
require('./data').getTests().then(function() { 

    // Now, you can run the tests. 
    mocha.run(function(failures){ 
    process.on('exit', function() { 
     process.exit(failures) 
    }) 
    }) 
}) 

test/index.js

var assert = require('assert') 

var tests = require('../data').tests 

var fn = function (value) { 
    return value + ' ' + 'pancake' 
} 

describe('test', function() { 
    describe('example', function() { 
    tests.forEach(function (test) { 
     it('should return ' + test.expect, function(){ 
     var value = fn(test.arg) 
     assert.equal(value, test.expect) 
     }) 
    }) 
    }) 
}) 

können Sie dann laufen Sie, indem Sie test-launcher.js ruht.

+0

Wie würde das im 'test'-Ordner funktionieren? Ich brauche es, um gut mit anderen Tests zu spielen, wenn ich "Mokka" und Code-Coverage betreibe? – ThomasReggi

+0

Nur Tests sollten sich im 'test'-Ordner befinden,' test-launcher.js' sollte sich entweder im Stammverzeichnis Ihres Projekts befinden oder in einem Verzeichnis, das andere Dienstprogramme enthält, falls Sie eines haben. Code Coverage sollte perfekt funktionieren, zum Beispiel mit istanbul, 'istanbul cover test-launcher.js' sollte dir geben, was du willst. Ich habe ein Beispielprojekt mit Code-Coverage erstellt, sehen Sie es sich an. https://github.com/tuvistavie/mocha-async-test –

-1

Ich würde die asynchrone Logik innerhalb der it Aufruf verschieben. Zu komplex mit Komponententests zu werden, ist ein Code-Geruch und irritiert wahrscheinlich nur andere Entwickler, wenn sie nicht nur fehlerhafte Tests debuggen und reparieren müssen, sondern auch Tests debuggen und korrigieren müssen, die nicht einmal definiert und ausgeführt werden, weil der ausgefallene Setup-Code Fehler aufweist . Versuche, nicht dorthin zu gehen.

var assert = require('assert') 
var Promise = require('bluebird') 

/* global describe, it*/ 

var fn = function(value) { 
    return value + ' ' + 'pancake' 
} 

function getTests() { 
    return Promise.resolve('kitty pancake') 
    .delay(500) 
    .then(function(value) { 
     return [ 
     { 
      'arg': 'kitty', 
      'expect': value 
     }, 
     { 
      'arg': 'doggy', 
      'expect': 'doggy pancake' 
     } 
     ] 
    }) 
} 

describe('example', function() { 
    it('should handle many things', function(done) { 
    getTests().then(function(tests) { 
     tests.forEach(function(test) { 
     var value = fn(test.arg) 
     assert.equal(value, test.expect, 'should return ' + test.expect) 
     }) 
     done() 
    }) 
    }) 
}) 
+0

Ich liebe diese Lösung, es scheint einfach, aber das Fehlen der Ausgabe von 'it' Aussagen liefert mir keine Informationen, wenn die Behauptung ich laufe ist erfolgreich. – ThomasReggi

1

Als Alternative zu Daniel Perez Methode können Sie auch use the command line switch --delay and start the tests on the first run() call. Durch asynchrones Verzögern der run() können Sie describe s und it s vorher asynchron registrieren. Beachten Sie jedoch, dass Sie run() nur einmal aufrufen können, d. H. Nur in einer Testdatei.So habe ich einen Asynchron-Test-Runner in ./test/ und jeden Asynchron-Test in ./testAsync/ erstellt:

// ./test/asyncRunner.js 
"use strict"; 

const allAsyncPaths = [ 
    "test-featureA", 
    "test-featureB", 
].map(a => "../testAsync/" + a); 

const allAsyncTestFunctions = allAsyncPaths.map(require); 

Promise.resolve({ 
}).then(function() { 
    const allPromises = allAsyncTestFunctions.map(a => a()); 
    return Promise.all(allPromises); 
}).then(function() { 
    run(); // mocha waits for run() because of --delay flag 
}).catch(function(err) { 
    console.error(err); 
}); 

und

// ./testAsync/test-featureA.js 
"use strict"; 
function asyncTestRegistrator() { 

    return Promise.resolve({ 
    }).then(function() { 
    return getTestsAsync(); 
    }).then(function(tests) { 

    describe('example', function() { 
    tests.forEach(function (test) { 
     it('should return ' + test.expect, function(){ 
     var value = fn(test.arg); 
     assert.equal(value, test.expect); 
     }); 
    }); 
    }); 
} 
module.exports = asyncTestRegistrator; 
0

Ich würde als unter den Asynchron/await mit delay option verwenden:

setTimeout(async() => { 
//get tests async 
const tests = await getTests() 

describe('example', async() => { 

    tests.forEach((test) => { 
    it(`test name: ${test.name} `,() => { 
    console.log(test.name) 
    }) 
}) 
}) 

run() 
}, 1000)