What is ts-sinon?
The ts-sinon package is a TypeScript-friendly wrapper around the Sinon.js library, which is used for creating spies, stubs, and mocks in JavaScript testing. It provides type-safe utilities that integrate seamlessly with TypeScript, making it easier to write tests with Sinon in TypeScript projects.
What are ts-sinon's main functionalities?
Spies
Spies are used to monitor the behavior of functions. In this example, a spy is created for a function, and after calling the function, we can check if it was called using `spy.called`.
const myFunction = () => {};
const spy = tsSinon.spy(myFunction);
spy();
console.log(spy.called); // true
Stubs
Stubs are used to replace functions with custom behavior. Here, a method of an object is stubbed to return a different value than it originally would.
const myObject = { myMethod: () => 'original' };
const stub = tsSinon.stub(myObject, 'myMethod').returns('stubbed');
console.log(myObject.myMethod()); // 'stubbed'
Mocks
Mocks are used to set expectations on function calls. In this example, a mock is created for an object's method, expecting it to be called once. The `verify` method checks if the expectations were met.
const myObject = { myMethod: () => {} };
const mock = tsSinon.mock(myObject);
mock.expects('myMethod').once();
myObject.myMethod();
mock.verify();
Other packages similar to ts-sinon
jest
Jest is a popular testing framework that includes built-in mocking capabilities. Unlike ts-sinon, Jest is a complete testing solution with its own test runner and assertion library, whereas ts-sinon focuses on providing Sinon.js functionalities with TypeScript support.
testdouble
Testdouble is a library for creating test doubles (spies, stubs, and mocks) similar to Sinon. It is designed to be simpler and more intuitive than Sinon, but it does not have the same level of TypeScript integration as ts-sinon.
proxyquire
Proxyquire is a library for overriding dependencies during testing. While it can be used to achieve similar outcomes as stubbing in ts-sinon, it focuses more on module dependency replacement rather than individual function behavior.
ts-sinon
Sinon extension providing functions to:
- stub all object methods
- stub interface
- stub object constructor
Prerequisites
- You have a version of Node.js >= v8.4.0
- You have installed Typescript
Installation
npm install --save-dev ts-sinon
or
yarn add --dev ts-sinon
Object stubs example
Importing stubObject function:
import { stubObject } from "ts-sinon";
- import as part of sinon singleton:
import * as sinon from "ts-sinon";
const stubObject = sinon.stubObject;
Stub all object methods:
class Test {
method() { return "original" }
}
const test = new Test();
const testStub = stubObject<Test>(test);
testStub.method.returns("stubbed");
expect(testStub.method()).to.equal("stubbed");
Partial stub:
class Test {
public someProp: string = "test";
methodA() { return "A: original" }
methodB() { return "B: original" }
}
const test = new Test();
const testStub = stubObject<Test>(test, ["methodA"]);
expect(testStub.methodA()).to.be.undefined;
expect(testStub.methodB()).to.equal("B: original");
Stub with predefined return values (type-safe):
class Test {
method() { return "original" }
}
const test = new Test();
const testStub = stubObject<Test>(test, { method: "stubbed" });
expect(testStub.method()).to.equal("stubbed");
Interface stubs example
Importing stubInterface function:
import { stubInterface } from "ts-sinon";
- import as part of sinon singleton:
import * as sinon from "ts-sinon";
const stubInterface = sinon.stubInterface;
Interface stub (stub all methods):
interface Test {
method(): string;
}
const testStub = stubInterface<Test>();
expect(testStub.method()).to.be.undefined;
testStub.method.returns("stubbed");
expect(testStub.method()).to.equal("stubbed");
Interface stub with predefined return values (type-safe):
interface Test {
method(): string;
}
const testStub = stubInterface<Test>({ method: "stubbed" });
expect(testStub.method()).to.equal("stubbed");
Object constructor stub example
Importing stubConstructor function:
import { stubConstructor } from "ts-sinon";
- import as part of sinon singleton:
import * as sinon from "ts-sinon";
const stubConstructor = sinon.stubConstructor;
Object constructor stub (stub all methods):
- without passing predefined args to the constructor:
class Test {
public someVar: number = 10;
method(): string {
return "value";
}
}
const testStub = stubConstructor(Test);
expect(testStub.method()).to.be.undefined;
testStub.method.returns("stubbed");
expect(testStub.method()).to.equal("stubbed");
expect(testStub.someVar).to.equal(10);
testStub.someVar = 20;
expect(testStub.someVar).to.equal(20);
- with passing predefined args to the constructor:
class Test {
constructor(public someVar: string, y: boolean) {}
}
const testStub = stubConstructor(Test, "someValue", true);
expect(testStub.someVar).to.equal("someValue");
Sinon methods
By importing 'ts-sinon' you have access to all sinon methods.
import sinon, { stubInterface } from "ts-sinon";
const functionStub = sinon.stub();
const spy = sinon.spy();
or
import * as tsSinon from "ts-sinon"
const functionStub = tsSinon.default.stub();
const spy = tsSinon.default.spy();
const tsStubInterface = tsSinon.stubInterface<T>();
Packages
Dependencies:
- Microsoft/TypeScript
- TypeStrong/ts-node
- sinonjs/sinon
Dev Dependencies:
- mochajs/mocha
- chaijs/chai
- domenic/sinon-chai
Tests
npm test