jsmock
Advanced tools
Comparing version 0.5.0 to 0.6.0
@@ -6,5 +6,5 @@ | ||
module.exports = { | ||
_: matcher.any, | ||
Mock: mock.Mock, | ||
UnexpectedCall: mock.UnexpectedCall | ||
UnexpectedCall: mock.UnexpectedCall, | ||
_: matcher.any | ||
} |
@@ -35,2 +35,9 @@ 'use strict'; | ||
function addAction(action) { | ||
if(this.actionsFinalized) { | ||
throw new Error('Action list already finalized for expectation'); | ||
} | ||
this.actions.push(action); | ||
} | ||
/** @class Expectation | ||
@@ -56,2 +63,3 @@ * | ||
this.cardinalityForced = false; | ||
this.actionsFinalized = false; | ||
} | ||
@@ -149,3 +157,3 @@ | ||
tryUpdateCardinality.call(this, 1); | ||
this.actions.push(new Action(action, 1)); | ||
addAction.call(this, new Action(action, 1)); | ||
return this; | ||
@@ -165,3 +173,3 @@ } | ||
tryUpdateCardinality.call(this, 2); | ||
this.actions.push(new Action(action, 2)); | ||
addAction.call(this, new Action(action, 2)); | ||
return this; | ||
@@ -176,9 +184,7 @@ } | ||
* Parameter passed for Action constructor | ||
* @returns {Expectation} | ||
* Returns current instance of the expectation for chaining. | ||
*/ | ||
willRepeatedly(action) { | ||
tryUpdateCardinality.call(this, -1); | ||
this.actions.push(new Action(action, -1)); | ||
return this; | ||
addAction.call(this, new Action(action, -1)); | ||
this.actionsFinalized = true; | ||
} | ||
@@ -185,0 +191,0 @@ |
@@ -89,2 +89,3 @@ 'use strict'; | ||
} | ||
this.expectations = {}; | ||
const err = (unresolved.length > 0) ? new Error('Unresolved expectations on functions: ' + unresolved.join(',')) : null; | ||
@@ -91,0 +92,0 @@ if(typeof done === 'function') { |
{ | ||
"name": "jsmock", | ||
"version": "0.5.0", | ||
"version": "0.6.0", | ||
"description": "Mocking framework for javascript", | ||
@@ -8,3 +8,3 @@ "main": "index.js", | ||
"test": "mocha", | ||
"test_coverage": "istanbul cover _mocha" | ||
"test_coverage": "istanbul cover _mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" | ||
}, | ||
@@ -27,4 +27,7 @@ "keywords": [ | ||
"chai": "^4.1.2", | ||
"mocha": "^4.0.1" | ||
"coveralls": "^3.0.0", | ||
"istanbul": "^0.4.5", | ||
"mocha": "^4.0.1", | ||
"mocha-lcov-reporter": "^1.3.0" | ||
} | ||
} |
117
README.md
[![npm Package](https://img.shields.io/npm/v/jsmock.svg?style=flat-square)](https://www.npmjs.org/package/jsmock) | ||
[![Build Status](https://travis-ci.org/kcwiakala/jsmock.svg?branch=master)](https://travis-ci.org/kcwiakala/jsmock) | ||
[![Coverage Status](https://coveralls.io/repos/github/kcwiakala/jsmock/badge.svg?branch=master)](https://coveralls.io/github/kcwiakala/jsmock?branch=master) | ||
@@ -43,2 +44,3 @@ # jsmock | ||
## Specifying Matcher | ||
@@ -53,3 +55,3 @@ Matcher validates that call of mocked function is valid for given expectation. If | ||
foo.bar(3,2); // OK - 3 > 2 | ||
foo.bar(1,4); // KO - excpetion thrown | ||
foo.bar(1,4); // KO | ||
@@ -69,16 +71,111 @@ fooMock.expectCall('bar', 1, 8); | ||
## Specifying Cardinality | ||
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. | ||
```javascript | ||
fooMock.expectCall('bar').times(2); // Expect bar to be called twice | ||
fooMock.expectCall('bar').atLeast(1); // Expect bar to be callet 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. | ||
## Specifying Actions | ||
Action is an object encapsulating function to be executed instead of original | ||
code on mocked object. Besides a function each action specifies also number of | ||
times it's expected to be called. Each expectation can have multiple actions | ||
defined, which will be executed in order of creation. | ||
Action is an object encapsulating function to be executed instead of the original | ||
code on mocked object. Each expectation can have multiple actions defined with | ||
specific cardinality. Actions are executed in the order of creation. | ||
```javascript | ||
fooMock.expectCall('bar') | ||
.willOnce((a,b) => a * b) // First call will return multiplication of arguments | ||
.willRepeteadly((a,b) => b) // All following calls will return second argument | ||
.willTwice((a,b) => a + b) // Second and third will return sum of arguments | ||
.willRepeteadly((a,b) => b); // All following calls will return second argument | ||
``` | ||
You need to pay attention to order of specifying actions. If an action with | ||
unlimited number of expected calls preceeds other actions, it will prevent their | ||
execution and cause mock to be invalid. | ||
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. | ||
```javascript | ||
fooMock.expectCall('bar') | ||
.willOnce(4) // Return 4 on first call | ||
.willTwice(7) // return 7 on next 2 calls | ||
.willRepeteadly(0); // All following calls will return 0 | ||
``` | ||
# Examples | ||
The *willRepeteadly* 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. | ||
### Actions and Cardinality | ||
Combination of cardinality and action specifiers can build virtually any expectation. | ||
```javascript | ||
fooMock.expectCall('bar') | ||
.times(5) // Total number of calls expected to be 5 | ||
.willOnce(3) // First call returns 3 | ||
.willRepeteadly(0); // Next 4 calls returns 0 | ||
fooMock.expectCall('bar') | ||
.atLeast(8) | ||
.willRepeteadly(1); // Will always return 1 | ||
``` | ||
## Verifying Mocks | ||
Mock object will yeld 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. | ||
```javascript | ||
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 expecations. | ||
## Cleaning Mocks | ||
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. | ||
```javascript | ||
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(); | ||
``` | ||
# Examples | ||
```javascript | ||
it('Should perform some fs action', (done) => { | ||
let fsMock = new Mock(fs); | ||
fsMock.expectCall('readdir') | ||
.matching(path => path === '/tmp') | ||
.willOnce((path, cb) => cb(null, ['a.js', 'b.js'])); | ||
foo.readTemp((files) => { | ||
expect(files).to.deep.equal(['a.js', 'b.js']); | ||
fooMock.verify(done); | ||
}); | ||
}); | ||
``` |
@@ -240,9 +240,2 @@ 'use strict'; | ||
}); | ||
it('Should return instance of current expectation', () => { | ||
let exp1 = new Expectation(); | ||
let exp2 = new Expectation(); | ||
expect(exp1.willRepeatedly(() => true)).to.be.equal(exp1); | ||
expect(exp2.willRepeatedly(() => false)).to.be.equal(exp2); | ||
}) | ||
@@ -252,6 +245,16 @@ it('Should create action with provided function', () => { | ||
exp.willRepeatedly(() => 4531); | ||
expect(exp.actions[0].execute()).to.be.equal(4531); | ||
exp = new Expectation(); | ||
exp.willRepeatedly(() => 'Hello World'); | ||
expect(exp.actions[0].execute()).to.be.equal(4531); | ||
expect(exp.actions[1].execute()).to.be.equal('Hello World'); | ||
expect(exp.actions[0].execute()).to.be.equal('Hello World'); | ||
}); | ||
it('Should block possibility of adding any more actions to the expectation', () => { | ||
let exp = new Expectation(); | ||
exp.willRepeatedly(4); | ||
expect(exp.willOnce.bind(exp, 1)).to.throw(Error); | ||
expect(exp.willTwice.bind(exp, 1)).to.throw(Error); | ||
expect(exp.willRepeatedly.bind(exp, 1)).to.throw(Error); | ||
}); | ||
}); | ||
@@ -258,0 +261,0 @@ }); |
@@ -70,2 +70,14 @@ 'use strict'; | ||
it('Should cleanup all previously setup expectations', () => { | ||
let a = new A(); | ||
let aMock = new Mock(a); | ||
aMock.expectCall('foo').willTwice(() => 4); | ||
aMock.expectCall('bar').willTwice(() => 4); | ||
a.foo(); | ||
a.bar(); | ||
expect(aMock.verify.bind(aMock)).to.throw(Error, 'Unresolved'); | ||
expect(a.foo.bind(a)).to.throw(UnexpectedCall); | ||
expect(a.bar.bind(a)).to.throw(UnexpectedCall); | ||
}); | ||
it('Should throw if there is at least one not saturated expectation', () => { | ||
@@ -78,5 +90,7 @@ let a = new A(); | ||
aMock.expectCall('foo').willTwice(() => 4); | ||
a.foo(1,2); | ||
expect(aMock.verify.bind(aMock)).to.throw(Error, 'Unresolved'); | ||
aMock.expectCall('bar').willOnce(() => 4); | ||
a.bar(3,4); | ||
@@ -95,2 +109,3 @@ expect(aMock.verify.bind(aMock)).not.to.throw; | ||
}); | ||
aMock.expectCall('foo').willTwice(() => 4); | ||
a.foo(1,2); | ||
@@ -101,2 +116,3 @@ aMock.verify(err => { | ||
}); | ||
aMock.expectCall('bar').willOnce(() => 4); | ||
a.bar(3,4); | ||
@@ -103,0 +119,0 @@ aMock.verify(err => { |
Sorry, the diff of this file is not supported yet
48169
1155
179
5