Now accepting guest editorial from SAP, Oracle, Workday and ServiceNow practitioners.Pitch a guide
The Sign-Off Table

Lesson 2 of 6

CAP service tests with cds.test

10 min

Listen to this lesson

0:00 / 6:28

CAP ships its own test support. cds.test starts a CAP server for your project inside the test process and gives you helpers to call it over HTTP or through the service API. Because the server runs with an in-memory database, mocked users and mocked remote services, a full service test suite runs in seconds on a laptop or in the pipeline.

Setting up

Add the test package as a development dependency with npm add -D @cap-js/cds-test; cds test -? confirms it works. Tests can run with Node's built-in test runner (node --test), with cds test (a thin wrapper around it) or with another common JavaScript test runner. CAP's documentation recommends writing runner-agnostic tests: use describe, it, the before and after hooks, and the expect function provided by cds.test, and avoid runner-specific mocking features. It also insists on one rule: call cds.test() first in each test file, before loading other CAP modules, so configuration is read from the right project. Runner-agnostic tests paid off with cds 10 (June 2026): @cap-js/cds-test 1.0 supports Vitest, and CAP is phasing out Jest, so teams that relied on Jest-specific mocking now have porting work that runner-agnostic suites avoid.

A first test file, test/fleet.test.js:
const cds = require('@sap/cds')
const { GET, POST, expect, defaults } = cds.test(__dirname + '/..')
defaults.auth = { username: 'agent' }
describe('FleetService', () => {
it('creates an inquiry with notes', async () => {
const { status } = await POST('/odata/v4/fleet/Inquiries', { salesOrder: '1000457', customer: '17100001', priority: 2, notes: [{ text: 'Customer called' }] })
expect(status).to.equal(201)
})
})
Sales order 1000457 and business partner 17100001 (Great Lakes Fleet Services) are Contoso's illustrative course data, loaded from test/data and the mocked Sales Order API, not real documents. The example uses CommonJS; in an ES module project, which is the default for projects created with cds 10, the file imports cds and passes the project folder with import.meta.dirname instead of __dirname.

cds.test runs the real CAP service inside the test process, so an HTTP test exercises the protocol, authorization and database in seconds.
The Sign-Off Table · thesignofftable.com/academy/sap-btp-301

What to test at service level

AreaExample tests for the fleet app
Declarative validationPriority 5 is rejected with 400; a missing salesOrder is rejected; an unknown topic code is rejected by @assert.target
Actions and handlerscloseInquiry without resolution returns 400; with resolution sets status Closed and closedBy to the caller
CompositionsDeep insert creates the inquiry and its notes; deleting the inquiry deletes its notes
AuthorizationEach cell of the role matrix: 401 anonymous, 403 for an agent calling closeInquiry, 404 for another customer's inquiry
Remote data useThe sales order list for a customer is built from the mocked Sales Order API with the expected filter
Error handlingA failed remote call produces a clear message, not a crash, and does not lose the inquiry

Service-level test areas, each with at least one positive and one negative case.

  1. Startcds.test launches the CAP server with in-memory SQLite, mocked auth and mocked remote services
  2. ArrangeReset data before each test so tests do not depend on each other; set the user
  3. ActSend an HTTP request with GET or POST, or call the service API through cds.connect.to
  4. AssertCheck status, payload and resulting database state with expect
  5. ReportThe runner reports results; the pipeline stores them as evidence
The shape of a CAP service test.
The Sign-Off Table · thesignofftable.com/academy/sap-btp-301

HTTP or service API?

cds.test supports both. HTTP calls go through the protocol adapter, so they test the OData API as consumers see it, including status codes and authorization. Calls through cds.connect.to('FleetService') skip the protocol layer, which is useful for testing service logic directly. For data isolation, the test helper offers a data reset that redeploys the database; CAP's documentation shows it in a beforeEach hook. Default request options, such as the user, can be set once with defaults and overridden per request with an auth option.

HTTP helpers test the API as consumers see it, while the service API skips the protocol layer to test logic in isolation; both start from reset data.
The Sign-Off Table · thesignofftable.com/academy/sap-btp-301
HTTP helpers (GET, POST, ...)Service API (cds.connect.to)
Goes throughOData protocol adapter, authentication, authorizationService layer directly
Best forAPI behavior, status codes, role matrixBusiness logic in isolation
ExamplePOST closeInquiry as agent expects 403Read inquiries and compare with a direct query
SpeedFastFaster
Two ways to exercise a CAP service in tests.
The Sign-Off Table · thesignofftable.com/academy/sap-btp-301

What would you do?

Kenji's team mocks the CAP service itself with the test runner's mocking features, replacing the generic provider with stubs that return fixed data, "to make tests faster". What should the reviewer say?

Key points
  • cds.test starts the real CAP service in the test process with in-memory data and mocks.
  • Call cds.test() first; write runner-agnostic tests with its expect function.
  • Test validation, actions, compositions, authorization, remote data use and error handling, each positive and negative.
  • Use HTTP helpers for API behavior and the service API for isolated logic.
  • Reset data per test; do not mock the CAP service itself.

Check your understanding · not graded

Lesson check

  1. 1. Which package provides cds.test in current CAP projects?

  2. 2. What must come first in a CAP test file?

  3. 3. Why reset data before each test?

  4. 4. Which approach tests status codes and authorization as consumers see them?