Product
Introducing License Enforcement in Socket
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
Light-weight test double library for easier testing of dependency injection style
code. Patterned somewhat after phpunit
, which looks like junit
I believe.
Can stub, spy, and mock classes, objects, the
system timers, require()
and http calls.
qmock
is testing framework agnostic; mocks can be used standalone. They are
integrated into the qnit
unit test runner.
qmock = require('qmock');
// mock an existing object
var mock = qmock.getMock(console);
// instrument log() and ensure that it is called with 'hello'
// full phpunit syntax should also work, ie
// mock.expects(qmock.twice()).method('log').with('hello');
mock.expects(2).method('log').with('hello');
mock.log('hello');
qmock.check(mock); // assertion error, called 1 times, expected 2
// with() is sticky, all subsequent calls must also match
mock.log('world');
qmock.check(mock); // assertion error, 'world' !== 'hello'
// methods don't have to already exist. create and call a stub method
// by specifying what it will return:
mock.expects(1).method('boom').will(qmock.throwError(new Error("BOOM!")));
mock.boom(); // error throw, BOOM!
qmock.getMock(master)
returns a mock object that is instanceof master
.
The master can be a class (constructor function) or an existing object.
The mock is a fully functional object, with some methods possibly stubbed out.
If master is a class (a constructor function), returns a mock object built with the given constructorArgs.
If master is an object, an identical object is cloned. The clone will be
instanceof the same class as master
, and will have the same own and inherited
properties as master
.
In both cases, some or all of the named methods are replaced by no-op stubs. If
methodNames
is given as falsy, no methods are stubbed; if an Array, the named
methods are stubbed; if not passed, all methods are stubbed.
Example:
var fakeLogger = qmock.getMock({}, ['log']);
fakeLogger.log("test message");
Build a mock object like getMock
but do not initialize the object. The returned
object will still have the instance, own and inherited properties of master
, but
will be completely un-initialized.
If master is an existing object, this call is identical to getMock
.
Stubs are stand-in methods that track and instrument calls. Spies are fully functional methods annotated with instrumentation. Their functionality overlaps.
A spy instruments an existing method (or function) and tracks calls made to it. The original method contiues to work exactly as before.
A stub temporarily replaces an existing method (or function), or creates an anonymous
function and spies on the replacement. The original method will not be accessible
until after it's restore
-d.
Spy on calls to the given function. Returns an instrumented function that tracks
calls to func
. If no func is given, an anonymous function is created to be spied
on, which can then be passed as eg a callback. Returns the spy function. The stats
are accessible as properties on the spyFunc
, or in its property spyFunc.stub
.
Example
var qmock = require('qmock');
var computeFunc = function(a, b) { return a + b };
var spyFunc = qmock.spy(computeFunc);
var c = spyFunc(1, 2);
computeFunc = spyFunc.restore();
// c => 3
// spyFunc.callCount => 1
// spyFunc.callArguments => [1, 2]
// spyFunc.callResult = 3
Spy on calls to the named method of the object. If the override
function is given,
the method will be replaced with the override. Returns a spy
function that holds
information about the calls made. The object method can be restored to the original
with spy.restore()
.
The returned spy
contains the call stats like qmock.stub()
, with additional
methods (see Stub and Spy API, below).
Example
var qmock = require('qmock');
var originalWrite = process.stderr.write;
process.stderr.write = qmock.spy(function(str, cb) {
console.log("would have written %d bytes", str.length);
if (cb) cb();
});
process.stderr.write("test message\n");
// => would have written 13 bytes
process.stderr.write = originalWrite;
process.stderr.write("another message\n");
// => another message
With no arguments, returns an instrumented anonymous function like qmock.spy()
.
Return an instrumented anonymous function to replace func
. restore()
returns
the original func
.
Example:
process.exit = qmock.stub(process.exit);
process.exit();
// did not exit!
process.exit = process.exit.restore();
Replace the named method of object
with an anonymous noop function or the specified
override, and return a stub method that will contain information about calls to the
method. This form can be used to suppress or rewrite method calls.
If an override function is not specified, a noop function is used (changed in 0.4.0). The noop function does not call its callback, if any.
If object
does not have a method methodName
, one will be created for it. The
overridden object property will be restored to its original value (or deleted if it
did not exist) upon stub.restore()
.
Use spy
to passively examine calls to an existing method or function.
Returns a stub
object that is updated with information about the last call's
arguments, return value, exception thrown, and callback arguments:
One-shot stub: stub the method like qmock.stub()
, but restore
the original
method after the first call.
One-shot spy: spy on the function or method like qmock.spy()
, but restore
the
original after the first call.
Make the stub return value
when called. Returns the stub
for call chaining.
Calling returns
on a spy converts it into a stub.
Make the stub call its callback with the provided values [val1, val2, ...]
. The callback
is assumed to be the first function in the stub argument list. Returns the stub
for chaining.
Calling yields
on a spy converts it into a stub.
The callback is invoked synchronously, before the stub returns. Use yieldsAsync
to
call back after a small pause.
Like stub.yields
, but invoke the callback asynchronously, after a short pause.
Make the stub return a Promise resolved to the value val
.
Make the stub return a Promise that rejects with the value val
.
Make the stub throw the given error
value. Returns the stub
for chaining.
If a stub both yields and throws, it will throw first and call the callback on the
next event loop tick.
Calling throws
on a spy converts it into a stub.
Make all subsequent returns
, yields
and throws
calls configure the n-th
(0-based) use-once retval. Call onCall(-1)
to restore the default behavior of
configuring the permanent retval.
Like stub.returns
, but only returns the value once. Creates a new use-once retval
and configures it to return value
. returnsOnce
actions are performed in sequence,
so stub.returnsOnce(1).returnsOnce(2)
will return first 1 then 2. Returns the stub
for call chanining.
After all stub.returnsOnce
values have been returned, all subsequent calls will
return the stub.returns
value.
Like stub.yields
, but calls back with these values only once. See also returnsOnce
.
The callback is invoked synchronously, before the stub returns. Use yieldsAsyncOnce
to call back after a small pause.
Like stub.yieldsOnce
but invoke the callback asynchronously, after a short pause.
Like stub.throws
, but throws only once. See also returnsOnce
.
Unhook the spy or stub, and restore the original method back onto the object. Returns the original spied-on/stubbed method, function, or property.
Return the n-th (0-based) call details. The details include the the call args
,
its returnValue
, and any exception
thrown.
Number of calls made to the stub.
Array with the arguments from the last call to the stub.
Last value returned from the stub function, undefined
if it threw an Error
.
The error generated by the last call to the stub function, null
if none. A
successful call following a call that threw replaces the error with null
.
Like stub.callError
, but error
is sticky, and contains the last error thrown by
any call to the stub.
If a spied-on method is passed an argument of type "function", it will be assumed to
be the method callback and will be instrumented to track what it returns. A copy of
the callback arguments with will be placed into spy.callCallbackArguments
. Only the
first function-type argument is instrumented.
Note: callbacks are not synchronized with calls to the stub, so the callback arguments may not be from the most recent call.
Note: qmock versions 0.10.2 and earlier looked for a callback only in the last argument position; qmock 0.11.0 and up look for the first argument of type "function".
Example:
var qmock = require('qmock');
var assert = require('assert');
var stub = qmock.stub(process, 'exit', function(){});
process.exit(1);
process.exit(2, 3);
console.log("did not exit");
// => did not exit
assert.equal(stub.callCount, 2);
assert.deepEqual(stub.callArguments, [2, 3]);
stub.restore();
process.exit();
// process exited, program stopped
console.log("this line will not appear");
// no output, line not reached
Return the argument vectors passed to the first 10 calls of the spied function.
For convenience, this information is also available in the spy.args
array.
Return the values returned by the first 10 calls to the spied function.
Also available as spy.returnValues
.
Return the errors thrown by the first 10 calls to the spied function. If no error
was thrown by a call, the array contains a null
entry for it.
Also available as spy.exceptions
.
Return the argument vectors passed to the stub callback. The callback is recognized
as a function passed as the last value in the stub arguments list. Note that
callbacks may be called out of order, so the returned argument may not match 1-to-1
the stub arguments passed in getAllArguments
.
Example
var qmock = require('./');
var spy = qmock.spy(process.stderr, 'write', function(str, cb) {
console.log("would have written %d bytes", str.length);
if (cb) cb();
});
process.stderr.write("test message\n");
// => would have written 13 bytes
spy.restore();
process.stderr.write("another message\n");
// => another message
mockTimers
overrides the system setImmediate, setTimeout, etc calls with mock
work-alikes that trigger under user control. unmockTimers
restores the system
timers.
Replace the nodejs timers functions setImmediate
, clearImmediate
, setTimeout
et al with mocked versions whose time is not linear and is not limited by real
time. Returns a clock object. To restore the timers back to their original
unmodified versions, use qmock.unmockTimers()
.
This function can be called any number of times, each call replaces the previous timers calls in effect with a new set. Note that any pending immediates and timeouts in the system timers will still trigger, but with follow-up timeouts queued into the mock.
Returns a mock timeouts clock
that controls the passage of events time:
Advances mock timers time by n
milliseconds (default 1). Immediates and timeouts
are run as they come due, immediates before timeouts. 0 milliseconds runs only the
immediates.
The array of immediate tasks that will execute on the next event loop tick
.
A hash indexed by the expiration timestamp of arrays of timeouts.
The current mock timers timestamp that is advanced by tick
.
Example:
var qmock = require('qmock');
var clock = qmock.mockTimers();
setTimeout(function() {
console.log("timeout");
setImmediate(function() {
console.log("immediate");
qmock.unmockTimers();
});
}, 10);
clock.tick(9);
// => (nothing)
clock.tick(1);
// => "timeout"
clock.tick(0);
// => "immediate"
Restore the global setImmediate
, setTimeout
etc functions back to their inital
original nodejs versions. Can be called any time. Note that any pending timeouts
in the mock timers can still be triggered with clock.tick()
.
mockRequire
overrides require
everywhere to return the mock value
for the named modules. unmockRequire
restores the system require
.
Arrange for require
of moduleName
to return replacement
in all sources,
even if moduleName
had been loaded previously. Calls to mockRequire
are
cumulative, each one defines one more module that will be mocked.
It is an error for moduleName
to be falsy.
Stub require
of moduleName
with the provided handler function, and return the
value it computes. Handler is invoked as handler(moduleName)
.
If moduleName
is provided, arrange for require
of moduleName
to load
the actual module and not the mock replacement value.
Without a module name, uninstall the mock require hooks and restore the
original unmodified system require
functionality. All previously defined
module mocks are cleared.
Helper function to restore the system to the state it was in before
the named module was ever require
-d. It deletes all cached copies of the
module from require.cache
, module.children
, module.parent.children
etc.
mockHttp
overrides http.request
and https.request
with mocks that return
user supplied values. unmockHttp
restores the system http functions.
Override http.request
and https.request
to redirect all web requests to the
provided handler. Each new request will make a call to handler
. Request and
response behavior and emulation is up to the handler. The handler is invoked
immediately after the caller receives the req
return object. This function can
be called at any time, each replaces the previous override. Restore the default
system request functionality with unmockHttp
.
The request
callback is passed the mock res
object or the res
supplied by the
handler as soon as mockResponse
event is emitted req.emit('mockResponse', [res])
.
Note that the handler gets a client-side http.ClientRequest
(what the client sends
to the server) and http.IncomingMessage
(what the client receives back), not the
usual server-side IncomingMessage
and ServerResponse
objects.
Example
qmock.mockHttp(function(req, res) {
req.emit('mockResponse');
res.emit('data', "mock data");
res.emit('end');
})
var req = http.request("http://localhost", function(res) {
res.on('data', function(chunk) {
console.log("got:", chunk);
})
res.on('end', function() {
qmock.unmockHttp();
})
})
// => got: mock data
Without arguments, mockHttp
mocks an http server, and returns the mock server
object. The mock server has methods to recognize and respond to calls to mocked
routes.
server = qmock.mockHttp();
server.when('http://localhost/test')
.end(200, 'Hello, test.');
Match the route against the condition. If the route matches condition
, the actions
that follow will be run to generate the response for the route. Only the first matching
condition will have its actions run.
The http.request
callback is called before the first matching action is run, and the
'end'
event is emitted when no more actions are left to run. Note that because the
actions that build the respones have not been run yet, the res.statusCode
and other
response fields may remain undefined until the res 'end'
event has been received.
Conditions:
string
- match the full url or the request pathname against the stringMETHOD:string
- match the full annotated url or annotated request pathname against the string,
The annotated url would look something like "POST:http://localhost:80/pathname".RegExp
- match the url or pathname against the regular expressionfunction(req, res)
- use the given function to test whether the route matchesExamples:
.when('http://localhost:80/') - match any http request to localhost port 80
.when(/\/test\//) - match any request with "/test/" in its pathname
.when(/^POST:/) - match any POST request
.when(/^/) - match any request
.when(function(req, res) { - match any request with Basic user:pass authorization
return (req._headers['authorization'].indexOf('Basic ') === 0);
})
An alias for server.when
.
Like server.when
, but the condition will be matched only once. After the first match,
it will not match any other request. This allows the mock to return different responses
to the same request. The matching actions are run in the order defined.
qmock.mockHttp()
.once('http://host/getNext')
.send(200, 'data1')
.once('http://host/getNext')
.send(200, 'data2')
.once('http://host/getNext')
.send(500, 'no more data');
// http.request('http://host/getNext') => 'data1', statusCode 200
// http.request('http://host/getNext') => 'data2', statusCode 200
// http.request('http://host/getNext') => 'no more data', statusCode 500
An alias for a condition that always matches the route, equivalent to .when(/.*/)
.
Define a default
as the very last condition, because conditions are tested in the
order defined and the default always matches all routes so no other conditions will
be tested.
The before
actions are run for all matched routes before their condition actions are run.
The after
actions are run for all matched routes after their condition actions are run.
Actions:
Set the response statusCode
and responseHeaders
, write the responseBody
, and
finish the response. No more data should be written after the response has been
finished.
Call the provided responseFunction
to generate the response.
Cause res
to emit a 'data'
event with the given chunk.
Set the response statusCode and headers.
Same as send
: set the statusCode, write the reply and finish the response.
Invoke the provided callout, let it adjust res
.
Pause for ms
milliseconds before continuing with the rest of the condition actions.
Emit an event on the res
object.
Emit the error event on the req
object.
Without arguments, replays the mock request: makes a real http request with the same arguments as the mock, and relays the real http response to the mock response.
With arguments, makes an http request to the specified url string or object, optionally with the given request body and request headers, and relays the real http response back to the mock response. Body, if specified, must be a string or Buffer.
The default request method is GET, use a uri object to override.
Here's an example that mocks just the third call, making actual web requests for the first, second, fourth and all subsequent calls:
// mock just the third call to 'localhost:80'
mock = qmock.mockHttp()
.once("http://localhost:80").makeRequest() // first call
.once("http://localhost:80").makeRequest() // second call
.once("http://localhost:80").send(404, 'override with Not Found')
.when("http://localhost:80").makeRequest() // all other calls
Example
var mockServer = qmock.mockHttp()
.when("http://localhost:1337/test/call")
.send(204)
.when("http://localhost:1337/test/error")
.emit('error', new Error("error 409"))
.send(409, "test error 409", { 'test-header-1': 'test-value-1' })
var req = http.request("http://localhost:1337/test/error", function(res) {
var response = "";
res.on('data', function(chunk) {
response += chunk;
})
res.on('end', function() {
assert.equal(res.statusCode, 409);
assert.equal(response, "test error 409");
assert.equal(res.headers['test-header-1'], 'test-value-1');
})
res.on('error', function(err) {
console.log("got err '%s'", err.message)
})
})
req.end("test request body");
// => got err 'error 409'
Restore the original system implementations for http.request
and https.request
.
This function can be called any time.
stub.resolves
and stub.rejects
stack
disrequire
under the package name as well (alias of unrequire),
upgrade disrequire to hugely improve worst case speedunrequire
code moved into the disrequire
package, fix makeRequest
call method handlingserver.makeRequest
mock http server call, fix onConsecutiveCalls to be able to return plain functionsstub.onCall
and stub.getCall
methods, document yieldsAsync
and yieldsAsyncOnce
.mockRequireStub
mockRequire()
functionality.on
, .once
and .default
mockHttpServer commands, make spy(func).restore() return func (not throw), upgrade to mongoid-1.1.3uri.pathmame
is now ignored, which might break tests that depended on it.req.setTimeout
, intercept request
even when called as a bare functionstub.called
for sinon compat, fix getMock(Constructor), fix extendWithMocks().getMockSkipConstructor,
fix mocks when have expects/method/check methods, fix QMock.expects() when mocked has expects() methodmockHttp()
methods write
, writeHead
, end
and emit
, document mockHttp()
spy()
stubOnce
and spyOnce
stub()
with a noop function if no override method is givenspy
functions, simple http mocking, test with qnitstub()
and mockTimers()
, initial spy()
inherit()
and disinherit()
calls: annotate the prototype (inherited properties) of the object,
for e.g. x = 3; inherit(x, 'a', 1); assert(x.a === 1)
FAQs
class and object mocking, method stubbing and spying
The npm package qmock receives a total of 63 weekly downloads. As such, qmock popularity was classified as not popular.
We found that qmock demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
Product
We're launching a new set of license analysis and compliance features for analyzing, managing, and complying with licenses across a range of supported languages and ecosystems.
Product
We're excited to introduce Socket Optimize, a powerful CLI command to secure open source dependencies with tested, optimized package overrides.