Why do we need Chorus?

Most developers are familiar with test driven development (TDD) principles and accept that design for testability affects the code we write.

TDD results in code which is structured in a way which makes it easy to unit test.
For example, a module might be written to depend on an abstraction or interface rather than a real data source, so that mock data or a mock service implementation can be injected.

However, unit testing is only one part of the picture.
What about component and integration testing?

Designing for integration testing

Techniques to ‘design for testability’ in integration tests are less well understood.
These tests require starting up one or more complete components in a testing environment. How might we design a component to be testable when running within an integration test environment? Furthermore, how might we test collaborations between components or end to end flows?

Often integration testing is left to the end of the development process.
In the worst case it is done by external team who have no input in the design or development process of the components they are charged with testing.

If a component is not designed to be testable, the only way to to test it might be to observe visible aspects of its output.
For example, by checking that a component has inserted data into a table in a database.

This has several drawbacks:

How Chorus solves the problem

Chorus presents a solution to the above problems by allowing the components to be developed with built in testing hooks which run within the components themselves.
These take the form of test step definitions which can be embedded in the code and invoked over the network, from a BDD-style test.

This means the code to trigger actions during tests and check any resulting conditions is developed within the components themselves, and is maintained alongside the component code by the original developers.

The role of the testing team (if indeed there still is one) is to create test features using the test steps which are ‘published’ by the various components which make up the integration testing environment. The test team may also sit with the developers to assist with adding test steps into the component source code.

When a component’s code changes, the test step implementations will naturally change along with it. Since the step definitions run within the components, they have access to the full in-memory runtime state, and nothing is inaccessible.

One quick note - not all test steps have to be published by a component.
It’s quite possible to provide some step implementations locally to the interpreter.

Isn’t embedding test code within a deployable component a bad thing?

On the contrary, it’s really the only sensible and maintainable way to design for testability in integration tests. Additionally, the exporting of test steps is disabled in production environments, and with a little extra effort the test code can be elided in production deployments if you so wish.