-->

Test fails then succeeds

2019-07-20 14:49发布

问题:

Click run a couple of times - these tests alternate between pass and fail.

http://jsfiddle.net/samselikoff/hhk6u/3/

Both tests require companies, but I don't know how to isolate the events. Any ideas?

Answer:

Jeferson is correct. One easy way to solve this, is to use events.once instead of events.on. This way you clean up your events from each test.

回答1:

You are running synchronous tests while the callbacks of the triggered events are asynchronous.

To fix that you have to implement an "asyncTest" and call the start function when the test assertions are ready to be collected.

Your second test was failing with the message:

Called start() while already started (QUnit.config.semaphore was 0 already)

teste Exactly because it was a synchronous test, already started and you were calling the start() method again.

And also in your first test, that doesn't specify a callback function, you have to wrap your async call in another function so you can call start() when the simulated AJAX call is ready.

I updated your JSFiddle with working code: http://jsfiddle.net/hhk6u/8/ The new code is:

QUnit.config.autostart = false;
QUnit.config.testTimeOut = 1000;

asyncTest('Some test that needs companies.', function() {
    function getCompanies() {
        var companies = new Companies();
        ok(1);
        start();
    }
    setTimeout(getCompanies, 500);
});

asyncTest('Some other async test that triggers a listener in companies.', function() {   
    var companies = new Companies();

    events.trigger("userSet:company", { name: "Acme", id: 1 });

    stop();
    events.on('fetched:departments', function(response) {
        console.log(response);
        deepEqual(response, [1, 2, 3]);
        start();
    });
});

Note that in the first test method I created a "getCompanies" function that will be called after an interval (500 milliseconds) that should be enough for the AJAX call to finish.

You have to adjust this time according to your needs, and also ajust "testTimeOut" value so your methods won't run indefinitely.

See QUnit config docs for more details: http://api.qunitjs.com/QUnit.config/



回答2:

Isn't your initial Fiddle potentially failing because you are not creating your event bus at the start of each test (in a setup() method), so your asynchronous event from the first test could be fired when the 2nd test is running and then cause the 2nd test to handle it twice, calling start() twice.

See my updated Fiddle http://jsfiddle.net/e67Zh/ it creates the event bus each time.

You might want to also set a timeout in your qunit tests for scenarios where the event doesn't fire.

/* Backbone code
*******************/
var Company = Backbone.Model.extend({});

var Companies = Backbone.Collection.extend({

    initialize: function() {
        var self = this;

        events.on("userSet:company", function(company) {
            self.selectedCompany = company;

            // Simulate an AJAX request
            setTimeout(function() {
                events.trigger("fetched:departments", [1, 2, 3]);
            }, 500);
        });
    },

    selectedCompany: ''
});


/* Tests
*******************/

module("test with new event bus each time", {
    setup: function() {
        events = _.clone(Backbone.Events);
    }
});

test('Some test that needs companies.', function() {
    var companies = new Companies();
    ok(1);
});

test('Some other async test that triggers a listener in companies.', function() {   
    var companies = new Companies();

    events.trigger("userSet:company", { name: "Acme", id: 1 });

    stop();
    events.on('fetched:departments', function(response) {
        console.log(response);
        deepEqual(response, [1, 2, 3]);
        start();
    });
});