Testing helpers #3
icebob posted onGitHub
- Start Date: 2020-02-01
- Target Version: 0.14
- Reference Issues: -
- Implementation PR:
Summary
We should create some testing tools/helpers in order to be more easily write tests for Moleculer services. E.g. mocking dependent services, waiting for emitted events, mocking broker.calls...etc
Detailed design
Creating broker for tests
createBroker
is a helper which creates ServiceBroker
instance for testing. It disables logger, add test middlewares & can register local mock services.
Base broker options which merged the passed options
const { EventCatcher, MockingCalls } = require("moleculer").Testing;
{
logger: false,
test: true,
middlewares: [
EventCatcher,
MockingCalls
]
}
Create a tester broker instance with default options
const { createBroker } = require("moleculer").Testing;
describe("Test", ()=> {
const broker = createBroker();
beforeAll(() => broker.start());
afterAll(() => broker.stop());
it("should create broker", () => {
// Tests
});
});
Create broker with custom broker options
const { createBroker } = require("moleculer").Testing;
describe("Test", ()=> {
const broker = createBroker({
nodeID: "node-100",
metrics: {
enabled: true
}
});
beforeAll(() => broker.start());
afterAll(() => broker.stop());
it("should create broker", () => {
// Tests
});
});
Create broker with options & mocked services
const { createBroker } = require("moleculer").Testing;
describe("Test", ()=> {
const postsListFn = jest.fn(async () => [1,2,3]);
const broker = createBroker({
nodeID: "node-100",
metrics: {
enabled: true
}
}, [
{
name: "posts",
actions: {
list: postsListFn
}
}
]);
beforeAll(() => broker.start());
afterAll(() => broker.stop());
it("should create broker", async () => {
const res = await broker.call("posts.list", { limit: 5 });
expect(res).toEqual([1,2,3]);
expect(postsListFn).toBeCalledTimes(1);
const ctx = postsListFn.mock.calls[0][0];
expect(ctx.params).toEqual({ limit: 5 });
});
});
Collect & wait for events
Need a testing middleware which wraps the emit
, broadcast
& broadcastLocal
methods & collect every call.
Register some asserting methods into ServiceBroker
instance.
Assertion methods
broker.test.eventEmitted("posts.updated")
broker.test.eventEmittedTimes("posts.updated")
broker.test.eventEmittedWithParams("posts.updated", { postID: 5 })
const { EventCatcher } = require("moleculer").Testing;
The
createBroker
register it as middleware automatically.
Wait for an emitted event
const { createBroker } = require("moleculer").Testing;
describe("Test", ()=> {
const postsListFn = jest.fn(async () => [1,2,3]);
const broker = createBroker();
broker.createService({
name: "posts",
events: {
async "posts.addedComment"(ctx) {
// Do something
await Promise.delay(1000);
ctx.emit("posts.updated", { postID: ctx.params.postID });
}
}
})
beforeAll(() => broker.start());
afterAll(() => broker.stop());
it("should emit 'posts.updated'", async () => {
broker.emit("posts.addComment", { postID: 5 });
await broker.test.waitForEvent("posts.updated");
expect(broker.test.eventEmitted("posts.updated")).toBe(true);
expect(broker.test.eventEmittedTimes("posts.updated")).toBe(1);
expect(broker.test.eventEmittedWithParams("posts.updated", { postID: 5 })).toBe(true);
broker.test.clearEvents(); // clearing saved event calls
});
});
Mocking action calls
Need a testing middleware which wraps the broker.call
method & collect every call. It can register mocked calls, as well.
Mock functions
broker.test.mockAction("users.get")
.withParams({ id: 5 })
.withMeta({})
.returnValue({ id: 5, name: "John", email: "john@moleculer.services" });
Assertion methods
broker.test.actionCalled("users.get")
broker.test.actionCalledTimes("users.get")
broker.test.actionCalledWithParams("users.get", { id: 5 })
const { createBroker } = require("moleculer").Testing;
describe("Test", ()=> {
const broker = createBroker();
broker.createService({
name: "posts",
actions: {
async get(ctx) {
const post = this.posts[ctx.params.id];
post.author = await ctx.call("users.get", { id: post.authorID });
return post;
}
}
})
beforeAll(() => broker.start());
afterAll(() => broker.stop());
it("should resolve author of post", async () => {
broker.test.mockAction("users.get").withParams({ id: 5 }).withMeta({}).returnValue({ id: 5, name: "John", email: "john@moleculer.services" });
const res = await broker.call("posts.get", { id: 2 });
expect(res).toEqual({
id: 2,
title: "Post title",
authorID: 5,
author: {
id: 5,
name: "John",
email: "john@moleculer.services"
}
});
expect(broker.test.actionCalled("users.get")).toBe(true);
expect(broker.test.actionCalledTimes("users.get")).toBe(1);
expect(broker.test.actionCalledWithParams("users.get", { id: 5 })).toBe(true);
broker.test.clearActions(); // clearing saved action calls
});
});