mm, mock mate
An simple but flexible mock(or say stub) package, mock mate.
Install
npm install mm --save-dev
Usage
var mm = require('mm');
var fs = require('fs');
mm(fs, 'readFileSync', function(filename) {
return filename + ' content';
});
console.log(fs.readFileSync('《九评 Java》'));
mm.restore();
console.log(fs.readFileSync('《九评 Java》'));
Support spy
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 ]);
API
.error(module, propertyName, errerMessage, errorProperties)
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) {
console.log(err);
mm.restore();
fs.readFile('/etc/hosts', 'utf8', function (err, content) {
console.log(err);
console.log(content);
});
});
.errorOnce(module, propertyName, errerMessage, errorProperties)
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) {
console.log(err);
fs.readFile('/etc/hosts', 'utf8', function (err, content) {
console.log(err);
console.log(content);
});
});
.data(module, propertyName, secondCallbackArg)
mm.data(fs, 'readFile', new Buffer('some content'));
fs.readFile = function (...args, callback) {
callback(null, new Buffer('some content'))
};
.dataWithAsyncDispose(module, propertyName, promiseResolveArg)
Support Symbol.asyncDispose
mm.dataWithAsyncDispose(locker, 'tryLock', {
locked: true,
});
locker.tryLock = async () => {
return {
locked: true,
[Symbol.asyncDispose](): async () => {
},
};
}
Run test with await using
should work:
mm.dataWithAsyncDispose(locker, 'tryLock', {
locked: true,
});
await using lock = await locker.tryLock('foo-key');
assert.equal(lock.locked, true);
.empty(module, propertyName)
mm.empty(mysql, 'query');
mysql.query = function (...args, callback) {
callback();
}
.datas(module, propertyName, argsArray)
mm.datas(urllib, 'request', [new Buffer('data'), {headers: { foo: 'bar' }}]);
urllib.request = function (...args, callback) {
callback(null, new Buffer('data'), {headers: { foo: 'bar' }});
}
.syncError(module, propertyName, errerMessage, errorProperties)
var mm = require('mm');
var fs = require('fs');
mm.syncError(fs, 'readFileSync', 'mock fs.readFile return error', {code: 'ENOENT'});
fs.readFileSync = function (...args) {
var err = new Error('mock fs.readFile return error');
err.code = 'ENOENT';
throw err;
};
.syncData(module, propertyName, value)
mm.syncData(fs, 'readFileSync', new Buffer('some content'));
fs.readFileSync = function (...args) {
return new Buffer('some content');
};
.syncEmpty
mm.syncEmpty(fs, 'readFileSync');
fs.readFileSync = function (...args) {
return;
}
.restore()
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.get({
path: '/foo'
}, function (res) {
console.log(res.headers);
var body = '';
res.on('data', function (chunk) {
body += chunk.toString();
});
res.on('end', function () {
console.log(body);
});
});
https.get({
path: '/foo'
}, function (res) {
console.log(res.headers);
var body = '';
res.on('data', function (chunk) {
body += chunk.toString();
});
res.on('end', function () {
console.log(body);
});
});
.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);
res.on('end', fucntion () {
console.log('never show this message');
});
});
req.on('error', function (err) {
console.log(err);
});
.classMethod(instance, method, mockMethod)
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);
License
MIT
Contributors
This project follows the git-contributor spec, auto updated at Sat Dec 09 2023 11:34:46 GMT+0800
.