Testing and Debugging
In this guide, you'll learn how to test your DBOS applications.
DBOS code can be easily tested in any unit-testing framework.
We'll show you how to write unit tests for the Hello
example class shipped by npx @dbos-inc/create
, using Jest.
Set Up Jest
If you haven't already, install jest.
npm i --save-dev jest @types/jest ts-jest
Set up a typical jest.config.js
, such as:
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testRegex: '((\\.|/)(test|spec))\\.ts?$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
modulePaths: ['./'],
};
Start a template test file, with a name such as main.test.ts
:
import { DBOS } from '@dbos-inc/dbos-sdk';
import { app, dbos_hello, Hello } from './main';
import request from 'supertest';
describe('operations-test', () => {
// Your test will go here...
});
To make it easy to run your tests, create a scripts
entry in package.json
:
"scripts": {
"test": "npx dbos migrate && jest"
}
Launching DBOS
Before executing any test code that uses DBOS, DBOS should be launched:
beforeAll(async () => {
await DBOS.launch();
});
See DBOS.launch
for launch options.
Configuring DBOS Prior To Launch
By default, DBOS.launch
loads the configuration from dbos-config.yaml
in the package root and uses this information to set up the runtime.
To load configuration from a different file, or to create a configuration in another way, call DBOS.setConfig
prior to launch:
const [cfg, rtCfg] = parseConfigFile({configfile: 'my-testing-dbos-config.yaml'});
DBOS.setConfig(cfg, rtCfg);
await DBOS.dropSystemDB(); // If you want a completely clean start
await DBOS.launch();
Testing Functions
Once DBOS is launched, a test can invoke workflows, transactions, and steps directly. Functions on the DBOS
class can be used to interact with workflows and check database status during the course of the test.
For example:
test('test-transaction', async () => {
const res = await Hello.helloTransaction('dbos');
expect(res).toMatch('Hello, dbos! You have been greeted');
// Check the greet count.
const rows = (await DBOS.queryUserDB('SELECT * FROM dbos_hello WHERE name=$1', ['dbos'])) as dbos_hello[];
expect(rows[0].greet_count).toBe(1);
});
In this code, we invoke Hello.helloTransaction
with the input string "dbos"
, and verify its output is as expected.
Testing HTTP Endpoints
If you are testing HTTP handling capabilities, these can be tested using a framework such as supertest.
Import the testing package:
import request from "supertest";
Launch your app's HTTP server, or launch DBOS with your app server:
beforeAll(async () => {
await DBOS.launch({ expressApp: app });
});
Use the handler callback during the course of unit-testing. In this code, we send a GET
request to our /greeting/dbos
URL and verify its response:
test('test-endpoint', async () => {
const res = await request(app).get('/greeting/dbos');
expect(res.statusCode).toBe(200);
expect(res.text).toMatch('Hello, dbos! You have been greeted');
});
Cleaning Up
Finally, after your tests, you should clean up DBOS and release its resources:
afterAll(async () => {
await DBOS.shutdown();
});
Run Tests
Now let's run the tests!
npm run test
You are responsible for setting and cleaning up database tables before and after tests.
In our example, we run Knex migrations with npx dbos migrate
as part of our testing script in package.json
, but this could have been done within the test instead.
You should see the test results similar to the following:
PASS src/main.test.ts
operations-test
✓ test-transaction (21 ms)
✓ test-endpoint (17 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 1.247 s, estimated 2 s
Further Reading
You can find the source code for this tutorial in operations.test.ts.
DBOS TestingRuntime
In prior versions of the TypeScript SDK, a TestingRuntime
was used to set up DBOS. This approach is obsolete.
- Instead of creating a
TestingRuntime
, just callDBOS.setConfig()
andDBOS.launch()
from your tests. - Calls to
TestingRuntime
functions can usually be replaced with identical calls toDBOS
functions. - In most cases, application functions can be called directly within the tests. Older app code can be invoked using
DBOS.invoke
instead of viaTestingRuntime.invoke
.