4

UPDATE 2-July-2013

Using the last approach with the wrapped anonymous function can introduce some strange testing behavior. If you expect a thrown error, but there is an error in the actual execution the test will pass, but will pass on any error and probably not the one you were expecting. I do two things, if its an error i am specifying i ensure the error text returned from the stub and the thrown error are the same. If it is from a third party library where i don't necessarily know the errors i will put some arbitrary value so that i know the passes are specific to the units i am testing. Example using sinon.js to stub some shizzle.

    it('should return an error if the save fails', function(){
        stubCall.restore();
        stubCall = sinon.stub(Provider, 'save').callsArgWith(1, new Error('Save Error'));

        (function(){
            User.create(fakeUser, function(err, user){
               if(err)
                throw err;
            });
        }).should.throw("Save Error");
    });

I am getting into Node.js and trying to do some Behaviour Driven Development(BDD) with Mocha and should.js (and sinon in there as well at some point).

One thing i am having problems with is testing errors returned by a call back, for instance this simple test:

it('should return an error if you try and execute an invalid Query object', function () {
        var stubQuery = {}; 

        Provider.execute(stubQuery, function (err) {
            //should.not.exist(err);
            should.have.property('message', 'Invalid Query Object');
        });
    });

with the function:

PostgresqlProvider.prototype.execute = function (query, cb) {

};

It doesn't matter what i try and test, the test always passes (should.exist, etc), and the only way i can get it to fail first is by adding cb(null); into the execute function, which kinda goes against what i am doing as i am trying to test before adding behaviour, not adding behaviour to fail a test.

I know i am doing some real newb mistake here, probably on a few levels but i am not grasping the testing of an error passed as a call back with is not thrown (which i am sure i could test easier)!

UPDATE

Using the code from Herman, i adjusted and that indeed words (the test is failing with no behavior defined)

        it('should return an error if you try and execute an invalid Query object', function () {
        var stubQuery = {};
        Provider.execute(stubQuery, function (err) {
            if (err) throw new Error(err);
        }).should.throw();
    });

issue now is i can't "catch" the error if sent in the callback to pass the test, the should.throw method doesn't get called, it just states that expected a throw to happen but didnt even though i am returning an error to the callback from my method. This could be down to scope but i am unsure if i should add some form of closure, and at what level.

UPDATE 2

Figured it out, i needed to wrap the call to the function inside a closure, not the callback (Doh!) and then place the assert (should.throw) at the end of the closure;

        it('should return an error if you try and execute an invalid Query object', function () {
        var stubQuery = {};
        (function(){
            Provider.execute(stubQuery, function (err) {     
                if (err) 
                    throw err;
            });
         }).should.throw();
    });
Modika
  • 6,192
  • 8
  • 36
  • 44
  • OK, I tried the code. Problem was that `should.throw()` checks the function `Provider`, not the callback inside to throw an exception, that is why your test pass. Use a `try..catch` block instead (an example is in my answer update), of course, you can come up with something more elegant than my example :) – Herman Junge Oct 25 '12 at 15:43
  • (ON UPDATE 2): LOL. I haven't figured out that wrapper `(function() Provider...`, good one! – Herman Junge Oct 25 '12 at 15:45
  • I am in a similar situation. Do you know if there is a way to test the error object without throwing it? I have been trying something like: ```error.should.eql(new Error('my error'))```, but it seems to always pass (even when the error text is wrong). – snapfractalpop Jun 14 '13 at 17:38
  • throwing seems to be the only way i can get it to work. if you want to test specific error text you can add that to the should throw check so: should.throw('my error'). throw is just validation that an error is being returned so i didnt want to get hung up on a minor detail – Modika Jun 19 '13 at 21:14

1 Answers1

0

You need to generate an exception inside your test function for the test to fail.

I'd add if (err) throw "Invalid query error " + err this way:

it('should return an error if you try and execute an invalid Query object', function () {
    var stubQuery = {}; 

    Provider.execute(stubQuery, function (err) {
        if (err) throw "Invalid query error " + err
    });
});

That should do.

(ON UPDATE)

should.throw() did not work for me either... I did this dirty hack to work the flow:

it('should return an error if you try and execute an invalid Query object', function () {
  var stubQuery = {}; 

  try {
    Provider.execute(stubQuery, function (err) {
      if (err) throw "Invalid query error " + err
    });
    // No error, keep on the flow
    noError ();
  } catch (e) {
    // Error, let's continue the flow there
    error (e)
  }

  function noError () {
    // The flow in the event we have no error
    // ... //
  }

  function error (errorObj) {
    // The flow, in the event we have error
    // ... //
  }

});

Hope this helps!

Herman Junge
  • 2,759
  • 24
  • 20
  • Hi herman, thanks for this, it worked (failed the test) but i cant get the should.throw to work to now pass it? i have updated the question with progress. – Modika Oct 25 '12 at 14:27
  • Going to mark this as the answer as it gets the original point and answer it, have updated the question to include code that is now working for me. – Modika Oct 25 '12 at 15:31