Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Mocking framework for javascript, inspired by googlemock C++ framework. This project is still under construction ...
jsmock
is published on npm
npm install --save-dev jsmock
All examples provided below assume using mocha
/chai
test framework, although
jsmock
can be used with any framework of your choice.
Mock provides an API to define and verify expectations on all function calls performed on reference to original object. A standard unit test involving mocks will consist of following steps:
const Mock = require('jsmock').Mock;
let foo = {
bar: (a, b) => {
return a + b
}
};
let fooMock = new Mock(foo);
Now fooMock
is a mock object wrapping foo
. All functions of original object
have been replaced and any call to foo.bar
will cause an UnexpectedCall error
to be thrown.
expect(foo.bar.bind(foo)).to.throw(Error);
Expectation
is a main component of a mock oriented test. It describes what kind
of interactions with mocked object are expected during test execution. In addition
Expectation
also defines the actions that should be taken to mock the original
object behavior.
Expectation
for given function is defined by 3 objects:
Matcher decides if current function call is valid for the expectation. Usually it means that function was called with expected argument list. Cardinality describes how many times the expected call should occur. Consequently Action List provides actions to be performed by mocked object for each call.
Expectation is created by calling expectCall
on mock object. Then it can be set up
with dedicated methods:
fooMock.expectCall('bar')
.matching(1, 4)
.times(4)
.willOnce((a, b) => a + b)
.willRepeatedly((a, b) => a - b);
Above code will create expectation on call to foo.bar(1,4)
that should happen
exactly 4 times. On the first call sum of the arguments will be returned, following
3 call with return their difference.
Matcher is an object checking that call of mocked function is valid for given expectation. If no explicit matcher is specified expectation will be executed for any call to mocked function. Matcher can be specified as a predicate or simply as an arguments list to be verified against actual call.
In jsmock matchers come in 3 flavours:
N
call arguments must match matcher argument listMatcher can be specified during Expectation
creation with expectCall
function,
or later with one of available Expectation
methods.
Method | Description |
---|---|
Mock.expectCall(fn, ...args) | Creates an expectation with Strict Argument Matcher from ...args |
Expectation.matching(...args) | Creates a Strict Argument Matcher from ...args |
Expectation.with(...args) | Alias of Expectation.matching |
Expectation.matchingAtLeast(...args) | Creates a Weak Argument Matcher from ...args |
Expectation.withAtLest(...args) | Alias of Expectation.matchingAtLeast |
Predicate Matcher is created automatically if one of above methods is called with only one argument that happens to be a function.
fooMock.expectCall('bar', (a,b) => a > b); // Predicate Matcher
foo.bar(3,2); // OK - 3 > 2
foo.bar(1,4); // KO
fooMock.expectCall('bar', 1, 8); // Strict Argument Matcher
foo.bar(1,8); // OK
foo.bar(1,0); // KO
fooMock.expectCall('bar').with(5,6); // Strict Argument Matcher
foo.bar(5,6); // OK
foo.bar(5,1); // KO
fooMock.expectCall('bar').matchingAtLeast(3); // Weak Argument Matcher
foo.bar(3,6); // OK
foo.bar(3,9); // OK
foo.bar(1,3); // KO
jsmock comes with a family of predefined argument type matchers, that can be helpful if we care more about the type of argument provided to the call than its actual value.
Matcher | Description |
---|---|
Matcher.ANY | Checks only presence of an argument in a call, doesn't care about actual type |
Matcher.OBJECT | Checks if given argument is an object |
Matcher.NUMBER | Checks if given argument is a number |
Matcher.STRING | Checks if given argument is a string |
Matcher.BOOLEAN | Checks if given argument is a boolean |
Matcher.FUNCTION | Checks if given argument is a function |
Matcher.ARRAY | Checks if given argument is an array |
const Matcher = require('jsmock').Matcher;
fooMock.expectCall('bar').with(Matcher.ANY, Matcher.NUMBER);
foo.bar(1,2); // OK
foo.bar('a',2); // OK
foo.bar([1,2,3], true); // KO
Cardinality specifies number of expected calls to given function. jsmock
provides
two ways of specifying expectation cardinality. It can be provided explicitly
through one of expectation methods, or it can be calculated automatically from
list of specified actions. If cardinality is specified explicitly it takes precedence
over one calculated from action list.
Method | Description |
---|---|
Expectation.times(N) | Matching call should occur exactly N times |
Expectation.atLeast(N) | Matching call should occur at least N times |
Expectation.atMost(N) | Matching call should occur at least once and at most N times |
Expectation.between(M,N) | Matching call should occur at least M times and at most N times |
fooMock.expectCall('bar').times(2); // Expect bar to be called twice
fooMock.expectCall('bar').atLeast(1); // Expect bar to be called at least one time
fooMock.expectCall('bar').atMost(4); // Expect bar to be called 1 - 4 times
fooMock.expectCall('bar').between(3,5); // Expect bar to be called 3 - 5 times
// Note that
fooMock.expectCall('bar').atMost(MaxCallCount);
// is equivalent of
fooMock.expectCall('bar').between(1, MaxCallCount);
Cardinality can be specified only once for given expectation.
Action is an object encapsulating function to be executed instead of the original mocked object code. Each expectation can have multiple actions defined with specific cardinality. Actions are executed in the order of creation.
fooMock.expectCall('bar')
.willOnce((a,b) => a * b) // First call will return multiplication of arguments
.willTwice((a,b) => a + b) // Second and third will return sum of arguments
.willRepeatedly((a,b) => b); // All following calls will return second argument
If action specifying method is feed with function it will use it as a callback for actual mocked function execution. If parameter of any other type is provided it will be returned to the caller at execution time.
fooMock.expectCall('bar')
.willOnce(4) // Return 4 on first call
.willTwice(7) // return 7 on next 2 calls
.willRepeatedly(0); // All following calls will return 0
The willRepeatedly method specifies action with unlimited number of potential calls, thus any other attempt to add more actions to the expectation will cause error. Also note that willRepeatedly doesn't return expectation object so it isn't suitable for chaining.
In nodejs
(and js
in general) it's very common to provide callback as the last argument
in the function call. Often the only purpose of the mock is to execute that callback with some
predefined arguments. This kind of action can be created easily using will...Invoke
versions
of action create methods
fsMock.expectCall('readdir')
.willOnceInvoke(null, ['a.js', 'b.js']);
// Which is equivalent of
fsMock.expectCall('readdir')
.willOnce((path, cb) => cb(null, ['a.js', 'b.js']));
Method | Description |
---|---|
Expectation.willOnce(k) | Adds an action to be executed once |
Expectation.willTwice(k) | Adds an action to be executed twice |
Expectation.willRepeatedly(k) | Adds an action to be executed until expectation cardinality is fulfilled |
Expectation.willOnceInvoke(...args) | Adds an invoker action to be executed once |
Expectation.willTwiceInvoke(...args) | Adds an invoker action to be executed twice |
Expectation.willRepeatedlyInvoke(...args) | Adds an invoker action to be executed until expectation cardinality is fulfilled |
Mock object will yield errors directly in case of unexpected calls or violation of cardinality upper bound (more calls than expected). Verification of cardinality lower bound has to be done explicitly by the user, at the end of the test.
let foo = new Foo();
let fooMock = new Mock(foo);
fooMock.expectCall('bar')
.times(2) // Lower bound of the cardinality is 2
.willRepeatedly(6);
expect(foo.bar()).to.be.equal(6); // We make only one call to bar
fooMock.verify(); // Will throw Error
Call to verify methods cleans up all previously setup expectations.
Creation of the mock over an existing object modifies its functions. To restore object to its original state you need to explicitly call cleanup method.
const fs = require('fs');
const Mock = require('jsmock').Mock;
let fsMock = new Mock(fs);
// Setup some expectations
fsMock.expectCall('readdir')
.willOnce((path, cb) => cb(null, ['index.html']));
testedObject.doSomeStuff();
fsMock.verify();
// Once you don't need to use fs in your tests
fsMock.cleanup();
Some examples of potential "real life" usage can be found in example.js test file.
FAQs
Mocking framework for javascript
The npm package jsmock receives a total of 0 weekly downloads. As such, jsmock popularity was classified as not popular.
We found that jsmock 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.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.