5

I've got a method that may throw an Error, but I'm having trouble writing a SinonJS/Mocha/Should unit test case for this condition.

Sample function under test:

function testError(value) {
  if (!value) {
    throw new Error('No value');
    return false;
  }
};

Sample test:

describe('#testError', function() {
  it('throws an error', function() {
    var spy = sinon.spy(testError);
    testError(false);
    spy.threw().should.be.true();
  });
});

This outputs:

  #testError
    1) throws an error


  0 passing (11ms)
  1 failing

  1) #testError throws an error:
     Error: No value
      at testError (tests/unit/js/test-error.js:6:14)
      at Context.<anonymous> (tests/unit/js/test-error.js:14:6)

I was expecting Sinon to catch the Error and allow me to spy on the throw, but it seems to fail the test instead. Any ideas?

I referred to Don't sinon.js spys catch errors? but the only solution there is to use expect. I'd prefer to keep with a single assertion library if possible.

Community
  • 1
  • 1
benjarwar
  • 1,794
  • 1
  • 13
  • 28

3 Answers3

14

It appears that this works inside a try/catch:

function foo() { throw new Error("hey!"); }
var fooSpy = sinon.spy(foo);
try {
  fooSpy();
} catch (e) {
  // pass
}
assert(fooSpy.threw());

Note that you have to call fooSpy, not foo itself.

But also note that .should.be.true() is not part of Sinon, so you're probably already using Chai or a similar library, in which case the expect(foo).to.have.thrown() or assert.throws(foo, someError) syntax seems much nicer.

Update: If you're using ShouldJS, looks like you can use should.throws. I still think this is nicer than using the Sinon version for this purpose.

nrabinowitz
  • 55,314
  • 10
  • 149
  • 165
  • 1
    Thanks, @nrabinowitz. Looks like ```should.throws``` might be the ticket. See my revised answer below. – benjarwar Oct 01 '15 at 22:54
1

Revised

Following @nrabinowitz's helpful advice, here's a solution that uses should.throws. This avoids using Sinon.spy altogether.

describe('#testError', function() {
  it('throws an error', function() {
    should.throws(function() {
      testError(false);
    });
  });
});
benjarwar
  • 1,794
  • 1
  • 13
  • 28
  • 1
    That doesn't do what you think. `stub.throws()` is pre-programming behavior for the stub, not asserting that it was called. Stubs do *not* call the underlying function - try this out with another function that does not throw, and you'll see the behavior unchanged. – nrabinowitz Oct 01 '15 at 21:56
  • Ah, you're right. Using ```stub``` was a false positive. I think using ```should.throws``` and calling the actual function under test works. And avoids using Sinon entirely. See my revised answer. – benjarwar Oct 01 '15 at 22:51
-2
            const bootstrap = async anyParam => {
                if(!anyParam){
                    throw new Error('test')
                }

                await anyParam()
            }

            const spy = sinon.spy(bootstrap)

            try {
                await spy();
            } catch (e) {
                expect(e.message).to.be.equal('test')
                spy.called = false
            }

            expect(spy.called).to.be.equal(false);
t33n
  • 171
  • 1
  • 10