Testing Backend Plugins and Modules
Utilities for testing backend plugins and modules are available in
@backstage/backend-test-utils
. This section describes those facilities.
Testing Backend Plugins and Modules
To facilitate testing of backend plugins and modules, the
@backstage/backend-test-utils
package provides a startTestBackend
function
which starts up an entire backend harness, complete with a number of mock
services. You can then provide overrides for services whose behavior you need to
adjust for the test run. The function also accepts a number of features (a
collective term for backend plugins and
modules), that are the subjects of the test.
The function returns an HTTP server instance which can be used together with
e.g. supertest
to easily test the actual REST service surfaces of plugins who
register routes with the HTTP router service API.
import { mockServices, startTestBackend } from '@backstage/backend-test-utils';
import request from 'supertest';
import { myPlugin } from './plugin.ts';
describe('myPlugin', () => {
it('can serve values from config', async () => {
const fakeConfig = { myPlugin: { value: 7 } };
const mockLogger = mockServices.logger.mock();
const { server } = await startTestBackend({
features: [
myPlugin(),
mockServices.rootConfig.factory({ data: fakeConfig }),
mockLogger,
],
});
const response = await request(server).get('/api/example/get-value');
expect(response.status).toBe(200);
expect(response.body).toEqual({ value: 7 });
expect(mockLogger.info).toHaveBeenCalledWith('Starting myPlugin');
});
});
This example shows how to access the mock service factories and pass options to them, which will override the default mock services.
The returned server also has a port()
method which returns the dynamically
bound listening port. You can use this to perform lower level network
interactions with the running test service.
mock services
The mockServices
object from @backstage/backend-test-utils
provides service factory functions, and mocks for all core services that you can use to verify interactions between plugin and services.
All mock services provide a factory function that is sufficient for most tests. Here's an example:
const fakeConfig = { myPlugin: { value: 7 } };
const { server } = await startTestBackend({
features: [
// Will provide access to the default urlReaders automatically.
mockServices.urlReader.factory(),
// Some factories accept options, in this example we provide some fake config.
mockServices.rootConfig.factory({ data: fakeConfig }),
],
});
There might be situations where you want to mock a service implementation to verify interactions, in those cases you can use the mock
function to get a mock object that you can interact with. Here's an example:
import { mockServices, startTestBackend } from '@backstage/backend-test-utils';
import { myPlugin } from './plugin.ts';
describe('myPlugin', () => {
it('should call use UrlReader', async () => {
const mockReader = mockServices.urlReader.mock();
await startTestBackend({
features: [myPlugin(), mockReader],
});
expect(mockReader.readUrl).toHaveBeenCalledWith('https://backstage.io');
});
it('should call use UrlReader again', async () => {
const partialImpl = jest.fn();
await startTestBackend({
features: [
myPlugin(),
// You could also supply partial implementations to the mock function.
mockServices.urlReader.mock({ readUrl: partialImpl }),
],
});
expect(partialImpl).toHaveBeenCalledWith('https://backstage.io');
});
});
Available services:
auth
cache
database
discovery
events
httpAuth
httpRouter
lifecycle
logger
permissions
rootConfig
rootHealth
rootHttpRouter
rootLifecycle
rootLogger
scheduler
urlReader
userInfo