guzzlerio / deride Goto Github PK
View Code? Open in Web Editor NEWMocking library based on composition
License: MIT License
Mocking library based on composition
License: MIT License
Provide access to individual calls to a method. Possibly return an array of each call in order with each being the arguments it was called with
Allow to stub an existing object so that all the methods names are taken from the object to populate the stub. This is a convenience method.
Look at adding the ability to assert against constructor args.
var Person = deride.construct(Person);
var bob = new Person('bob');
bob.expect.constructedWith('bob');
In needing to tests out some reconnection logic, I have the need to be able to do something like:
connectionFactory.setup.connect
.toResolveWith(mockConnection)
.twice()
.and.then
.toRejectWith(new Error('Boom')
describe('multi', function() {
it('only uses the stub x times', function() {
bob.setup.greet
.toReturn('alice')
.twice()
.and.then
.toReturn('sally');
bob.greet().should.eql('alice');
bob.greet().should.eql('alice');
bob.greet().should.eql('sally');
bob.greet().should.eql('sally');
});
it('only uses the stub x times and then falls back', function() {
var normalResult = bob.greet('alice');
bob.setup.greet
.toReturn('alice')
.twice();
bob.greet('alice').should.eql('alice');
bob.greet('alice').should.eql('alice');
should(bob.greet('alice')).eql(normalResult);
});
describe('also supports when specific arguments are provided', function() {
it('only uses the stub X times when called with matching args', function() {
var normalResult = bob.greet('talula');
var normalSimon = bob.greet('simon');
bob.setup.greet
.when('simon')
.toReturn('alice')
.twice();
// default Person behaviour
should(bob.greet('talula')).eql(normalResult);
// overridden behaviour
bob.greet('simon').should.eql('alice');
bob.greet('simon').should.eql('alice');
// default Person behaviour
should(bob.greet('simon')).eql(normalSimon);
});
it('falls back to default stub behaviour after X matching invocations', function() {
bob = deride.wrap(bob);
bob.setup.greet
.toReturn('talula')
.but.when('simon')
.toReturn('alice')
.times(2);
// default stubbed behaviour for non matching invocation
bob.greet('alice').should.eql('talula');
// stubbed behaviour for 1st matching invocation
bob.greet('simon').should.eql('alice');
// stubbed behaviour for 2nd matching invocation
bob.greet('simon').should.eql('alice');
// falls back to default stubbed behaviour for other matching invocations
bob.greet('simon').should.eql('talula');
// default stubbed behaviour for non matching invocation
bob.greet('alice').should.eql('talula');
});
});
});
I would like to be able to provide a function to when
which is invoked with the args at runtime and which is used to evaluate which overridden func to use.
It's the issue of wanting to setup a when
and you have an object as the arg but you don't care about (or are unable to predict) all of the fields.
My usage is that I have a delegate which is invoked when a message is put onto the DLE queue in RabbitMQ.
dleConsumer.setup.when(function(msg){
var content = JSON.parse(msg.content.toString());
return content.resource === 'talula';
}).toDoThis(done);
The issue I have is that the dleConsumer
will be invoked with any messages that end up on the DLE and I need to only care about ones which match my criteria.
it('can provide a predicate to when', function(done) {
var func = deride.func();
func.setup.when(function(msg) {
var content = JSON.parse(msg.content.toString());
return content.resource === 'talula';
}).toDoThis(done);
var msg = {
//...
//other properties that we do not know until runtime
//...
content: new Buffer(JSON.stringify({
resource: 'talula'
}))
};
func(msg);
});
Hi,
As requested by James.
Currently trying to test that we would handle the two different outcomes from restler correctly by using a deride stub.
However struggling to get the event emitters to work??
self.read = function(id, callback) {
restler
.get(url)
.on('success', function(person) {
console.log('sucess');
return callback(null, person);
})
.on('fail', function(err) {
console.log('fail');
return callback(err, null);
});
}
Add debug output when stubbed methods are called.
Currently I do this often:
var mapper = deride.stub(['map']);
mapper.setup.map.toDoThis(function(a, b, cb) {
debug('mapper.map', a, b);
cb();
});
It would be good to just be able to use .toCallbackWith
.
Reset the counts on all methods.
Using 0.4.0 the test sample below passes, but >=0.4.1 fails. Some issue with the upgrade of lodash to 4.5.1.
it('booooom', function() {
var obj = deride.stub(['send']);
obj.send(['a', 'b'], function() {});
obj.expect.send.called.withArgs(['a', 'b']);
});
produces:
Expectations
1) booooom
0 passing (14ms)
1 failing
1) Expectations booooom:
AssertionError: Expected send to be called with: a,b
+ expected - actual
-false
+true
at assertArgsWithEvaluator (lib/deride.js:118:9)
at Object.withArgs (lib/deride.js:66:9)
at Context.<anonymous> (test/test-deride.js:124:32)
When #45 is complete, the debug output will be prefixed with something like:
deride:stub
deride:wrap
deride.func
Add the ability to override the debug prefix per stub.
For example:
var mapper = deride.stub(['map'], { prefix: 'mymodule:deride:mapper' });
I cannot for the life of me get to the bottom of this one to give you a code sample which I appreciate doesn't help, but something has changed which is resulting in the serialize method throwing an error and I'm hoping you'll have an a-ha moment seeing the error.
Uncaught TypeError: Converting circular structure to JSON
at JSON.stringify (<anonymous>:null:null)
at serializeArgs (node_modules/deride/lib/deride.js:489:21)
at Object.call (node_modules/deride/lib/deride.js:294:19)
at Object.removeHandler (node_modules/deride/lib/deride.js:511:46)
Again, same test is fine on 1.1.0.
Use GIT Branching strategy - git flow
withArgs should evaluate equivalence. A further feature should be made called something like withExactArgs so that it uses strict equality on the actual object. The change for withArgs should simply be a strict equality of the JSON.stringify results of the expected and actual.
It would be useful to be able to assert that a method was called using a regex pattern to match on.
var bob = deride.stub(['greet']);
bob.setup.greet.toReturn('hello');
bob.greet('The inspiration for this was that my colleague was having a look at other mocking frameworks and mentioned to me that they do not work when using Object.freeze in the objects to enforce encapsulation. This library builds on composition to create a mocking library that can work with objects which are frozen.');
bob.expect.greet.called.withMatch(/^The inspiration for this was/);
Change the tests over to using arrow functions
reported by @jamlen
Support ES6 classes
so given:
class Person {
foo() {
console.log('foo');
}
greet(person) {
console.log('Howdy ' + person);
}
}
this should work (but doesn’t):
let bob = new Person();
bob.greet('sam') // => Howd'y sam
bob = deride.wrap(bob);
bob.greet('sam') // => bob.greet is not a function
Currently you can only stub a function using deride.func()
but I need to wrap an existing function to allow the execution to call the real method but be able to attach the expect
ations.
Expected usage:
var f = function (name) { return 'hello ' + name; };
var func = deride.func(f);
assert(func('bob'), 'hello bob');
func.expect.called.withArg('bob');
Currently there is withArgs
but you need to know (and care) about all of the arguments passed. You might only be interested in a subset of these.
Therefore add a withArg
function which you can select which argument (maybe by index, maybe by name if possible) to assert against.
My use case is that I am using matchExactly()
to test an expected call which is part of a large promise chain.
The promise chain then modifies further down the line the argument the first call was made with. I would expect deride to lock down and/or freeze the arguments for the initial expectation I setup if not mutated further down the line.
Sample failing test:
describe('copy by reference', function () {
var bob;
beforeEach(function testSetup() {
bob = deride.stub(['greet']);
bob.setup.greet.toResolve();
});
var mutatedObject = {
test: 'abc'
};
beforeEach(function sampleInvocationMutatingObject(done) {
bob.greet(mutatedObject)
.then(function () {
mutatedObject.test = '123';
done();
});
});
it('should not expect mutated object', function () {
bob.expect.greet.called.matchExactly({
test: 'abc' // this fails but only passes with { test: '123' }
});
});
});
Changing this function to cloneDeep fixes the problems - thoughts?
function call() {
calledWithArgs[timesCalled++] = _.cloneDeep(arguments);
}
Thoughts?
If the method signature contains a function before the callback, then toCallbackWith
will currently invoke that as the callback. This should be changed to expect the callback as the last argument which is a function.
For example:
bob.setup.greet.toCallbackWith([null, 'hello']);
bob.greet('sally', function(){
done('this is not the callback');
}, function(err, msg) {
msg.should.eql('hello');
done();
});
Long time no speak folks.
I'm still using this library quite extensively and also have a few other teams at ThoughtWorks on it too. After upgrading one of my projects to 1.2.0
this morning I had some failing tests, upon investigation it appears that I can no longer override the behaviour of a given expect.
Take the following example:
'use strict';
const deride = require('deride');
const thing = deride.wrap({ example: () => {} });
thing.setup.example.toCallbackWith([null, 1]);
thing.setup.example.toCallbackWith([null, 2]);
thing.example((err, number) => {
console.log(number);
});
On 1.1.x
, the result is 2
, on 1.2.0
the result is 1
.
This causes us some issues because we have a whole bunch of tests that have an initial thing.setup.example
, and then further down the line change the behaviour of thing.setup.example
to do something else. An example is we have a generic stub API which we use across multiple tests, and in some of them we want to override the default behaviour that's configured as part of the stub to do something slightly different.
support the creation of a single mocked function not attached to an object.
To allow a given method to emit an event when called. The original method will also be invoked and the response returned.
bob.setup.greet.toEmit('testing', 'arg1', {a: 1});
bob.on('testing', function(a1, a2) {
a1.should.eql('arg1');
a2.should.eql({a:1);
done();
});
bob.greet('bob');
Split the tests out into different files. Make it a little easier to navigate to the different types of tests.
As per the assert library, calls such as:
mockExec.expect.exec.called.times(1);
Should have a secondary parameter that allows you to return a bespoke error message.
There are certain async methods that also return a sync result, for example:
var child = exec('ls -al', function(err, result) {
console.log(result);
});
In this example, I need child.pid
and result
.
If I'm stubbing this method, I could do with being able to do both:
mockExec.setup.exec.toDoThis(function(command, callback) {
setTimeout(function() {
callback();
}, 100);
return {
pid: 12345
};
});
mockExec.setup.exec.toReturn({
pid: 12345
});
It would be great if when using called.withArg(arg)
& called.withArgs(arg)
it produced output which was not expected true but was false
.
Ideally it would be nice if the output was what it was actually call with.
Add support for mocking promise resolution and rejection.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.