-
Notifications
You must be signed in to change notification settings - Fork 19
Testing Your Code
All code contributed to the project should be tested, to do this we are using Mocha with Sinon and Chai for our tests.
Before continuing with this guide I recommend you are familiar with these three frameworks.
We follow a consistent layout for all our tests, the main things being: the file name matches the name of the file being tested (but suffixed with "Test"), the top level describe
block is named the same of the class, and inner describe
blocks are the name of the method.
File Being Tested: src/commands/MyCommand.ts
class MyCommand extends Command {
constructor() {}
async run(message: Message, args: string[]): Promise<void> {}
}
Test of File Being Tested: test/commands/MyCommandTest.js
describe("MyCommand", () => {
describe("constructor()", () => {
// Constructor tests go here.
});
describe("run()", () => {
// Run tests go here.
});
});
In the code you want to test you may have dependancies (such as an API) that you do not actually want to call. You can get around this issue by stubbing the dependancy using Sinon.
File Being Tested: src/commands/MyCommand.ts
import SomeService from "../services/SomeService";
class MyCommand extends Command {
...
async run(): Promise<void> {
const test = await SomeService.doSomething();
message.channel.send(test);
}
}
Test of File Being Tested: test/commands/MyCommandTest.js
import { createSandbox, SinonSandbox } from "sinon";
import SomeService from "../../src/services/SomeService";
describe("MyCommand", () => {
...
describe("run()", () => {
let sandbox: SinonSandbox;
beforeEach(() => sandbox = createSandbox());
afterEach(() => sandbox.restore());
it("calls the service", async () => {
// We are stubbing SomeService.doService() - replacing it's logic to return "Hello World!"
const someServiceStub = sandbox.stub(SomeService, "doService").resolves("Hello World");
await new MyCommand().run();
expect(someServiceStub.toBeCalled()).to.equal(true);
});
});
});