Git Product home page Git Product logo

eventspec's Introduction

Eventspec (WIP)

Eventspec is a behavioural contract testing framework for event-driven architectures in Nodejs.

Unlike typical contract testing (like Pact), Eventspec aims to formalise the hidden behavioural assumptions between services inherent in event-driven architectures.

These assumptions may be along the lines of:

  • After Service A emits event A, Service B will emit event B
  • After Service A emits event A, then event B, Service B will emit event C

Eventspec deals primarily in testing the correct sequence of events, rather than their exact payload.

Producers & Consumers

In an event driven architecture, both sides of a contract are typically both publishing events. We define the Producer as the service upon whose behaviour another service depends.

Tests are written by the consumer and executed by the producer. This allows the team working on the Producer service to understand their behavioural obligations to their consumers.

Use Eventspec alongside a contract testing framework like Pact. You will typically want a lot more schema contract tests than behavioural tests, as EDAs are typically used to minimise coupling. Your philosophy for using Eventspec should be to use as little as possible to protect core business value generating behaviours.

Example: Consumer spec

service('serviceB')
  .dependOn('serviceA', () => {
  describe('label cancellation', () => {
    it('allows a pre-booked label to be cancelled', () => {
      send('PARCEL TYPE SELECTED');
      receive('LABEL BOOKED');
      send('ORDER REJECTED');
      receive('LABEL CANCELLED'); 
    });
    it('does not cancel a label after it has been picked up', () => {
      send('PARCEL TYPE SELECTED');
      receive('LABEL BOOKED');
      send('SHIPMENT PICKED UP', { from: 'serviceC' });
      send('ORDER REJECTED');
      doNotReceive('LABEL CANCELLED'); // default timeout 10s 
    })
  })
})

The test case above:

  • Declares that service B depends on service A: Service A will execute the test written by service B
  • specifies events that will be sent by the consumer service (B), and events it expects in return
  • specifies an event sent by another service (C)
  • specifies an event it expects not to receive

We define the events used in our specs separately as follows:

events(() => {
  defineEvent('PARCEL TYPE SELECTED', {
    event: {
      type: 'PARCEL_TYPE_SELECTED',
      payload: {
        fulfilmentOrder: {
          id: '123abc',
        },
        parcel: {
          heighMm: 1200,
          widthMm: 100,
          depthMm: 3000
        }
      }
    }
  });
  // etc
})

Example: Producer configuration

Producer tests are executed alongside a running instance of the service under test. You could even initialise your service with a test specific runtime in your beforeAll hook.

configureService('serviceA', {
  beforeAll: async () => {
    await setupSeedData();
    await startServer({ eventSpecMode: true });
  },
  beforeEach: async () => {
    await resetSeedData();
  },
  from: {
    serviceB: {
      eventDispatcher: async (event) => {
        await axios.post('/test/webhook/serviceB', event);
        // you could even call your event handling code directly
      },
    },
    serviceC: {
      eventDispatcher: async (event) => {
        await axios.post('/test/webhook/serviceC', event);
      },
    },
  }, 
});

Your server has to run alongside your tests because we are actually going to capture the event publication during a test run. For example:

import { mockPublish } from 'eventspec';

export const publishEvent = async (event: Events) => {
  if (process.env.EVENTSPEC_TEST === 'true') {
    await mockPublish(event);
    return;
  }
  await pubsub.topic('some-topic').publishMessage({ json: event });
}

eventspec's People

Contributors

antman261 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.