An simple but flexible mock(or say stub) package, mock mate.
$ npm install mm --save-dev
var mm = require('mm');
var fs = require('fs');
mm(fs, 'readFileSync', function(filename) {
return filename + ' content';
});
console.log(fs.readFileSync('《九评 Java》'));
// => 《九评 Java》 content
mm.restore();
console.log(fs.readFileSync('《九评 Java》'));
// => throw `Error: ENOENT, no such file or directory '《九评 Java》`
If mocked property is a function, it will be spied, every time it called, mm will modify .called
, .calledArguments
and .lastCalledArguments
. For example:
const target = {
async add(a, b) {
return a + b;
},
};
mm.data(target, 'add', 3);
assert.equal(await target.add(1, 1), 3);
assert.equal(target.add.called, 1);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 1, 1 ]);
assert.equal(await target.add(2, 2), 3);
assert.equal(target.add.called, 2);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ], [ 2, 2 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 2, 2 ]);
If you only need spy and don't need mock, you can use mm.spy
method directly:
const target = {
async add(a, b) {
await this.foo();
return a + b;
},
async foo() { /* */ },
};
mm.spy(target, 'add');
assert.equal(await target.add(1, 1), 2);
assert.equal(target.add.called, 1);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 1, 1 ]);
assert.equal(await target.add(2, 2), 4);
assert.equal(target.add.called, 2);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ], [ 2, 2 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 2, 2 ]);
var mm = require('mm');
var fs = require('fs');
mm.error(fs, 'readFile', 'mock fs.readFile return error');
fs.readFile('/etc/hosts', 'utf8', function (err, content) {
// err.name === 'MockError'
// err.message === 'mock fs.readFile return error'
console.log(err);
mm.restore(); // remove all mock effects.
fs.readFile('/etc/hosts', 'utf8', function (err, content) {
console.log(err); // => null
console.log(content); // => your hosts
});
});
Just like mm.error()
, but only mock error once.
const mm = require('mm');
const fs = require('fs');
mm.errorOnce(fs, 'readFile', 'mock fs.readFile return error');
fs.readFile('/etc/hosts', 'utf8', function (err, content) {
// err.name === 'MockError'
// err.message === 'mock fs.readFile return error'
console.log(err);
fs.readFile('/etc/hosts', 'utf8', function (err, content) {
console.log(err); // => null
console.log(content); // => your hosts
});
});
mm.data(fs, 'readFile', new Buffer('some content'));
// equals
fs.readFile = function (...args, callback) {
callback(null, new Buffer('some content'))
};
mm.empty(mysql, 'query');
// equals
mysql.query = function (...args, callback) {
callback();
}
mm.datas(urllib, 'request', [new Buffer('data'), {headers: { foo: 'bar' }}]);
// equals
urllib.request = function (...args, callback) {
callback(null, new Buffer('data'), {headers: { foo: 'bar' }});
}
var mm = require('mm');
var fs = require('fs');
mm.syncError(fs, 'readFileSync', 'mock fs.readFile return error', {code: 'ENOENT'});
// equals
fs.readFileSync = function (...args) {
var err = new Error('mock fs.readFile return error');
err.code = 'ENOENT';
throw err;
};
mm.syncData(fs, 'readFileSync', new Buffer('some content'));
// equals
fs.readFileSync = function (...args) {
return new Buffer('some content');
};
mm.syncEmpty(fs, 'readFileSync');
// equals
fs.readFileSync = function (...args) {
return;
}
// restore all mock properties
mm.restore();
.http.request(mockUrl, mockResData, mockResHeaders) and .https.request(mockUrl, mockResData, mockResHeaders)
var mm = require('mm');
var http = require('http');
var mockURL = '/foo';
var mockResData = 'mock data';
var mockResHeaders = { server: 'mock server' };
mm.http.request(mockURL, mockResData, mockResHeaders);
mm.https.request(mockURL, mockResData, mockResHeaders);
// http
http.get({
path: '/foo'
}, function (res) {
console.log(res.headers); // should be mock headers
var body = '';
res.on('data', function (chunk) {
body += chunk.toString();
});
res.on('end', function () {
console.log(body); // should equal 'mock data'
});
});
// https
https.get({
path: '/foo'
}, function (res) {
console.log(res.headers); // should be mock headers
var body = '';
res.on('data', function (chunk) {
body += chunk.toString();
});
res.on('end', function () {
console.log(body); // should equal 'mock data'
});
});
.http.requestError(mockUrl, reqError, resError) and .https.requestError(mockUrl, reqError, resError)
var mm = require('mm');
var http = require('http');
var mockURL = '/foo';
var reqError = null;
var resError = 'mock res error';
mm.http.requestError(mockURL, reqError, resError);
var req = http.get({
path: '/foo'
}, function (res) {
console.log(res.statusCode, res.headers); // 200 but never emit `end` event
res.on('end', fucntion () {
console.log('never show this message');
});
});
req.on('error', function (err) {
console.log(err); // should return mock err: err.name === 'MockHttpResponseError'
});
class Foo {
async fetch() {
return 1;
}
}
const foo = new Foo();
const foo1 = new Foo();
mm.classMethod(foo, 'fetch', async () => {
return 3;
});
assert(await foo.fetch() === 3);
assert(await foo1.fetch() === 3);