bendrucker / sinon-as-promised

Sugar methods for sinon.js stubs for working with promises
MIT License
137 stars 13 forks source link

Doesnt work with Q #4

Closed tusharmath closed 10 years ago

tusharmath commented 10 years ago

I am trying to make it work with Q and unfortunately its not working.

Q = require 'q'
sinonAsPromised = require('sinon-as-promised') Q

            # Stubbing the method which is called internally
            @mod.crud.create = sinon.stub().resolves 'updated-document'

            # Returns the promise which was stubbed
            @mod._create @req, @res
            .should.eventually.equal 'updated-document'

Error thrown

   AssertionError: expected [Function] to equal 'updated-document'
tusharmath commented 10 years ago

Found the solution - Q.Promise needs to be passed to sinonAsPromised

bendrucker commented 10 years ago

Correct. You need to pass a Promise constructor. If you're working on a new library, you should consider choosing a promise library with a better API and stronger feature set (Bluebird).

tusharmath commented 10 years ago

@bendrucker I am looking for a Promise framework which has a self contained mocking module to manage tests more efficiently. Not sure if bluebird is capable of doing so.

bendrucker commented 10 years ago

I have no clue what you mean by that. An example would be helpful.

tusharmath commented 10 years ago

My apologies for not being clear. The problem is that I wanted to use a module which makes my tests Synchronous. The fact that I am using a promise everywhere is making my code very difficult to test. If there was a Promise Library which would make all my code Sync it would be super easy.

For Example

#Stub the create method which will be called by @mod._create
@crudP.cruds.FakeResource.create = sinon.stub().rejects error

#Calling the method under test (Making sure the test returns a promise)
@mod._create @req, @res
.then => 
    # The worst part is putting this piece of code inside a callback
    @res.send.calledWith error
    .should.be.ok
bendrucker commented 10 years ago

Angular requires you to flush $q promises synchronously. That's because those promises need to integrate with the digest cycle. Bluebird does allow you to use a custom scheduler and to my knowledge it is the only library capable of that sort of behavior. That said, I'd highly recommend against going down that route. There's no need and it just adds a bunch of complexity. Promises are not difficult to test. Mocha supports returning promises from your tests. Combine that with Bluebird's bind method instead of relying on CoffeeScript to generate a closure and sinon-chai and you can make your test a whole lot more readable and useful.

it('should call res.send with the error', function () {
  sinon.stub(this.crudP.cruds.FakeResource, 'create').rejects(error);
  return this.mod_create(this.request, this.response)
    .bind(this)
    .then(function () {
      this.res.send.should.have.been.calledWith(error);
    });
});
tusharmath commented 10 years ago

That’s yet another approach that I tried. The biggest challenge is - what happens if this.mod_create() doesn’t return a promise? As in, though it is using promises internally, I don’t have access to them thru any public method/property. In such a scenario, I have two options

  1. Mock the promises, and remote control them externally using mock-promises or something like that.
  2. Expose the private promises publicly.

What are your thoughts?

Regards, Tushar Mathur tusharmath@gmail.com tusharm.com http://tusharm.com/ +91 96-20-826576

On Oct 31, 2014, at 10:21 PM, Ben Drucker notifications@github.com wrote:

Angular requires you to flush $q promises synchronously. That's because those promises need to integrate with the digest cycle. Bluebird does allow you to use a custom scheduler https://github.com/petkaantonov/bluebird/blob/master/API.md#promisesetschedulerfunction-scheduler---void and to my knowledge it is the only library capable of that sort of behavior. That said, I'd highly recommend against going down that route. There's no need and it just adds a bunch of complexity. Promises are not difficult to test. Mocha supports returning promises from your tests. Combine that with Bluebird's bind method instead of relying on CoffeeScript to generate a closure and sinon-chai and you can make your test a whole lot more readable and useful.

it('should call res.send with the error', function () { sinon.stub(this.crudP.cruds.FakeResource, 'create').rejects(error); return this.mod_create(this.request, this.response) .bind(this) .then(function () { this.res.send.should.have.been.calledWith(error); }); }); — Reply to this email directly or view it on GitHub https://github.com/bendrucker/sinon-as-promised/issues/4#issuecomment-61291252.

bendrucker commented 10 years ago

Unless there's a very good reason you should not use promises "internally" like you'd use a library like async to coordinate some callbacks. You should always be chaining things. Trying to manually resolve a bunch of hard to reach promises in testing is just going to make your tests brittle.