Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing helpers #3

Open
icebob opened this issue Feb 1, 2020 · 3 comments
Open

Testing helpers #3

icebob opened this issue Feb 1, 2020 · 3 comments
Labels
Change: Minor Module: Core Stage: 2 Feature is planned, it will be implemented

Comments

@icebob
Copy link
Member

icebob commented Feb 1, 2020

  • 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
    });
});
@IssueHuntBot
Copy link

@icebob has funded $10.00 to this issue.


@IssueHuntBot
Copy link

@icebob has funded $40.00 to this issue.


@IssueHuntBot
Copy link

@activitypods has funded $50.00 to this issue.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Change: Minor Module: Core Stage: 2 Feature is planned, it will be implemented
Projects
None yet
Development

No branches or pull requests

2 participants