admin管理员组

文章数量:1310513

I'm very new to unit tests, mocha, and should.js, and I'm trying to write a test for an asynchronous method that returns a promise. Here is my test code:

var should = require("should"),
    tideRetriever = require("../tide-retriever"),
    moment = require("moment"),
    timeFormat = "YYYY-MM-DD-HH:mm:ss",
    from = moment("2013-03-06T00:00:00", timeFormat),
    to = moment("2013-03-12T23:59:00", timeFormat),
    expectedCount = 300;

describe("tide retriever", function() {
    it("should retrieve and parse tide CSV data", function() {
        tideRetriever.get(from, to).then(
            function(entries) { // resolve
                entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
            },
            function(err) { // reject
                should.fail("Promise rejected", err);
            }
        );
    });
});

When I manually test the tideRetriever.get method, it consistently resolves an array of 27 elements (as expected), but the test will not fail regardless of the value of expectedCount. Here is my simple manual test:

tideRetriever.get(from, to).then(
    function(entries) {
        console.log(entries, entries.length);
    },
    function(err) {
        console.log("Promise rejected", err);
    }
);

I can also post the source for the module being tested if it's necessary.

Am I misunderstanding something about Mocha or should.js? Any help would be greatly appreciated.

I'm very new to unit tests, mocha, and should.js, and I'm trying to write a test for an asynchronous method that returns a promise. Here is my test code:

var should = require("should"),
    tideRetriever = require("../tide-retriever"),
    moment = require("moment"),
    timeFormat = "YYYY-MM-DD-HH:mm:ss",
    from = moment("2013-03-06T00:00:00", timeFormat),
    to = moment("2013-03-12T23:59:00", timeFormat),
    expectedCount = 300;

describe("tide retriever", function() {
    it("should retrieve and parse tide CSV data", function() {
        tideRetriever.get(from, to).then(
            function(entries) { // resolve
                entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
            },
            function(err) { // reject
                should.fail("Promise rejected", err);
            }
        );
    });
});

When I manually test the tideRetriever.get method, it consistently resolves an array of 27 elements (as expected), but the test will not fail regardless of the value of expectedCount. Here is my simple manual test:

tideRetriever.get(from, to).then(
    function(entries) {
        console.log(entries, entries.length);
    },
    function(err) {
        console.log("Promise rejected", err);
    }
);

I can also post the source for the module being tested if it's necessary.

Am I misunderstanding something about Mocha or should.js? Any help would be greatly appreciated.

Share Improve this question asked Jun 5, 2014 at 22:51 SimpleJSimpleJ 14.8k13 gold badges61 silver badges96 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

UPDATE

At some point Mocha started to support returning Promise from test instead of adding done() callbacks. Original answer still works, but test looks much cleaner with this approach:

it("should retrieve and parse tide CSV data", function() {
    return tideRetriever.get(from, to).then(
        function(entries) {
            entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
        }
    );
});

Check out this gist for plete example.

ORIGINAL

CAUTION. Accepted answer works only with normal asynchronous code, not with Promises (which author uses).

Difference is that exceptions thrown from Promise callbacks can't be caught by application (in our case Mocha) and therefore test will fail by timeout and not by an actual assertion. The assertion can be logged or not depending on Promise implementation. See more information about this at when documentation.

To properly handle this with Promises you should pass err object to the done() callback instead of throwing it. You can do it by using Promise.catch() method (not in onRejection() callback of Promise.then(), because it doesn't catch exceptions from onFulfilment() callback of the same method). See example below:

describe("tide retriever", function() {
    it("should retrieve and parse tide CSV data", function(done) {
        tideRetriever.get(from, to).then(
            function(entries) { // resolve
                entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
                done(); // test passes
            },
            function(err) { // reject
                done(err); // Promise rejected
            }
        ).catch(function (err) {
            done(err); // should throwed assertion
        });
    });
});

PS done() callback is used in three places to cover all possible cases. However onRejection() callback can be pletely removed if you don't need any special logic inside it. Promise.catch() will handle rejections also in this case.

When testing asynchronous code, you need to tell Mocha when the test is plete (regardless of whether it passed or failed). This is done by specifying an argument to the test function, which Mocha populates with a done function. So your code might look like this:

describe("tide retriever", function() {
    it("should retrieve and parse tide CSV data", function(done) {
        tideRetriever.get(from, to).then(
            function(entries) { // resolve
                entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
                done();
            },
            function(err) { // reject
                should.fail("Promise rejected", err);
                done();
            }
        );
    });
});

Note that the way Mocha knows this is an async test and it needs to wait until done() is called is just by specifying that argument.

Also, if your promise has a "pleted" handler, which fires both on success and failure, you can alternatively call done() in that, thus saving a call.

More info at: http://mochajs.github.io/mocha/#asynchronous-code

本文标签: javascriptshouldjs not causing mocha test to failStack Overflow