Given that I have two ES6 classes.
This is class A:
import B from 'B'; class A { someFunction(){ var dependency = new B(); dependency.doSomething(); } }
And class B:
class B{ doSomething(){ // does something } }
I am unit testing using mocha (with babel for ES6), chai and sinon, which works really great. But how can I provide a mock class for class B when testing class A?
I want to mock the entire class B (or the needed function, doesn't actually matter) so that class A doesn't execute real code but I can provide testing functionality.
This is, what the mocha test looks like for now:
var A = require('path/to/A.js'); describe("Class A", () => { var InstanceOfA; beforeEach(() => { InstanceOfA = new A(); }); it('should call B', () => { InstanceOfA.someFunction(); // How to test A.someFunction() without relying on B??? }); });
Typically when mocking a dependency, a dummy class is provided with many of the same methods as the original. These methods do not provide functionality, but they may just return predictable values that we can use for testing purposes.
If the dependency does not depend on anything persistent or external, the only benefit you gain from mocking it is that the test will work properly even if the dependency is wrong - but that's assuming the mock works properly. For that you need to either: Write a mock that emulates the dependency completely.
Dependency injection is a way to scale the mocking approach. If a lot of use cases are relying on the interaction you'd like to mock, then it makes sense to invest in dependency injection. Systems that lend themselves easily to dependency injection: An authentication/authorization service.
You can use SinonJS to create a stub to prevent the real function to be executed.
For example, given class A:
import B from './b'; class A { someFunction(){ var dependency = new B(); return dependency.doSomething(); } } export default A;
And class B:
class B { doSomething(){ return 'real'; } } export default B;
The test could look like: (sinon < v3.0.0)
describe("Class A", () => { var InstanceOfA; beforeEach(() => { InstanceOfA = new A(); }); it('should call B', () => { sinon.stub(B.prototype, 'doSomething', () => 'mock'); let res = InstanceOfA.someFunction(); sinon.assert.calledOnce(B.prototype.doSomething); res.should.equal('mock'); }); });
EDIT: for sinon versions >= v3.0.0, use this:
describe("Class A", () => { var InstanceOfA; beforeEach(() => { InstanceOfA = new A(); }); it('should call B', () => { sinon.stub(B.prototype, 'doSomething').callsFake(() => 'mock'); let res = InstanceOfA.someFunction(); sinon.assert.calledOnce(B.prototype.doSomething); res.should.equal('mock'); }); });
You can then restore the function if necessary using object.method.restore();
:
var stub = sinon.stub(object, "method");
Replaces object.method with a stub function. The original function can be restored by callingobject.method.restore();
(orstub.restore();
). An exception is thrown if the property is not already a function, to help avoid typos when stubbing methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With