Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to stub a standalone utility function? #562

Closed
giannico opened this issue Sep 12, 2014 · 12 comments

Comments

Projects
None yet
@giannico
Copy link

commented Sep 12, 2014

Many node modules export a single function (not a constructor function, but a general purpose "utility" function) as its "module.exports". Is it possible to use Sinon.js to stub this standalone function?

// some module, "sum.js" that's "required" throughout the application
module.exports = function(a, b) {
    return a + b;
};

// test.js
var sum = require('sum');
...

beforeEach(function() {
    sumStub = sinon.stub(sum);
    // throws: TypeError: Attempted to wrap undefined property undefined as function
});

afterEach(function() {
   sumStub.restore();
});
...

Is there any way to achieve this?

@cjohansen

This comment has been minimized.

Copy link
Contributor

commented Sep 12, 2014

Unfortunately not.

@cjohansen cjohansen closed this Sep 12, 2014

@mroderick

This comment has been minimized.

Copy link
Member

commented Sep 12, 2014

For npm you can use https://github.com/thlorenz/proxyquire or similar. Michael Feathers would call this a link seam.

It's not elegant, but doable.

Once you have that in place, you can use Sinon as you normally would.

In the long run, you might want to move your architecture towards object seams, but it's a solution that works today. Similar projects exist for RequireJS.

@rektide

This comment has been minimized.

Copy link

commented Mar 13, 2015

function MyFunction(){}
module.exports = function(){ return module.exports.MyFunction.apply(this, arguments) }
module.exports.MyFunction = MyFunction

Then you can stub require('./MyFunction').MyFunction and the rest of your code will without change see the stubbed edition.

💫 😵 💫

@rmehner

This comment has been minimized.

Copy link

commented Jun 6, 2015

Stumbled across the same thing the other day, here's what I did:

const proxyquire = require('proxyquire')
const sinon = require('sinon')
const sum = sinon.stub()

const ModuleWithDependency = proxyquire('module', {
  'sum': sum
})

works pretty well for our case.

@glortho

This comment has been minimized.

Copy link

commented Dec 14, 2015

If using CommonJS:

const myStubbedModule = function( absoluteModulePath ) {
  const stub = sinon.stub();
  require.cache[ require.resolve( absoluteModulePath ) ] = stub;
  return stub;
}

Note: Depending on whether you're transpiling you may need to do:

require.cache[ require.resolve( absoluteModulePath ) ] = {
  default: stub,
  exports: stub
}
@rektide

This comment has been minimized.

Copy link

commented May 16, 2016

Often during tests I'll need to be inserting one stub for one specific test. The wrapper-function approach I took lets me modify the codebase and insert my stubs whenever I want, without having to either take a stub-first approach or play whack-a-mole with modules having references to the other modules I'm trying to stub and replace-in-place.

I've had a number of code reviews where people have pushed me towards hacking at the Node module layer, via proxyquire, mock-require, &c, and it starts simple and seems less crufty, but becomes a very difficult challenge of getting the stubs needed into place during test setup. With proxyquire at least one can proxyquire() a micro-/fixture- sized version of the app, something top level, & all stubs will be brought in during it's load, but tackling this at a JS language level rather than Node module level continues to strike me as significantly more straightforward, and easier to manage consistently and without danger (caveat: so long as one remembers to restore).

@caiogondim

This comment has been minimized.

Copy link

commented Dec 1, 2016

I made this module to more easily stub modules https://github.com/caiogondim/stubbable-decorator.js

@sinonjs sinonjs deleted a comment from eoaiu Sep 15, 2017

@Grzegorzsa

This comment has been minimized.

Copy link

commented Jun 1, 2018

I was just playing with Sinon and found simple solution which seem to be working - just add 'arguments' as a second argument

const sumStub = sinon.stub(sum, 'arguments');
sumStub.withArgs(2, 2).returns(4);
sumStub.withArgs(3, 3).returns(6);
@harryi3t

This comment has been minimized.

Copy link

commented Jun 21, 2018

Try this

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});
@jacquesdev

This comment has been minimized.

Copy link

commented Jan 30, 2019

@harryi3t - thanks that worked for me.

@elliottregan

This comment has been minimized.

Copy link

commented Apr 15, 2019

@harryi3t That didn't work for me, using ES Modules.
Error: can't redefine non-configurable property "default"

@fatso83

This comment has been minimized.

Copy link
Contributor

commented Apr 16, 2019

@elliottregan ES Modules are not stubbable per the STANDARD. We even have tests covering this behaviour. You can still do it, though, as I discuss here.

A lot of people are not actually testing ES Modules, but transpiled ES Modules (using Webpack/Babel, etc). The resulting ES5 uses getters to emulate how ES Modules work. You might be doing that, but try the simple route I suggest in the linked thread. mocha --register ... gets you a long way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.