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

Lesson 4 of 5

Test doubles

10 min

Listen to this lesson

0:00 / 9:38

Once a dependency can be replaced, something has to replace it. You can write a test double by hand: a small local class that implements the interface and returns fixed data. For many dependencies, though, SAP ships frameworks that create doubles for you, including for things you cannot put behind an interface, such as a database table or a CDS view. Knowing which framework fits which dependency is most of the skill.

Stubs, mocks and fakes

  • Stub: returns canned answers. "For customer Great Lakes Fleet Services, the agreement is 45.00 per unit."
  • Mock: a stub that also checks how it was called, and fails the test if the expected call did not happen. "The logger must be called once with message type E."
  • Fake: a working but simplified implementation, such as an in-memory table instead of the database.

All three are test doubles. Prefer stubs; use mock-style verification only when the interaction itself is the behavior you need to prove. Clean ABAP warns against mocking what the test does not need, because over-specified tests break on harmless refactoring.

Which framework for which dependency

Depended-on componentFrameworkEntry point
Classes and interfacesHand-written double or the ABAP OO Test Double FrameworkCL_ABAP_TESTDOUBLE
Database tables or CDS entities read with ABAP SQLABAP SQL Test Double FrameworkCL_OSQL_TEST_ENVIRONMENT
Logic inside a CDS view entityCDS Test Double FrameworkCL_CDS_TEST_ENVIRONMENT
Function modulesFunction Module Test Double FrameworkCL_FUNCTION_TEST_ENVIRONMENT
Authority checks (classic AUTHORITY-CHECK)Authority check test helperCL_AUNIT_AUTHORITY_CHECK
RAP business objectsTransactional buffer double or mock EML APICL_BOTD_TXBUFDBL_BO_TEST_ENV, CL_BOTD_MOCKEMLAPI_BO_TEST_ENV

SAP's test double frameworks, as summarized in SAP's ABAP Unit material and ABAP cheat sheets. Check availability in your release in ADT.

The ABAP OO Test Double Framework

CL_ABAP_TESTDOUBLE creates a double for an interface (or a non-final class) at runtime. You configure it in two statements: first cl_abap_testdouble=>configure_call( double )->returning( value ), then a call on the double that names the method and its input, which tells the framework which call the configuration applies to. You can also raise exceptions, ignore parameters and set expected call counts, then check them with verify_expectations. The framework does not cover local classes or interfaces, classes declared FINAL, FOR TESTING or CREATE PRIVATE, or constructors with mandatory parameters; for those, write the double by hand.

CL_ABAP_TESTDOUBLE is configured in two statements: what to return, then a call that names the method and input it applies to.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-205

SQL and CDS test doubles

The ABAP SQL Test Double Framework redirects ABAP SQL in the code under test from the real table or CDS entity to a double that the test fills. No design change is needed: Kenji's class can keep its SELECT on ZCMC_CORE_AGR. The CDS Test Double Framework serves a different purpose: it tests the logic inside a CDS view entity (joins, calculations, filters) by replacing the view's own data sources with doubles. SAP's RAP unit testing tutorial uses both, CDS doubles for reads of the BO's view and SQL doubles for the tables it touches.

The SQL double isolates ABAP code from its tables; the CDS double tests the logic inside a view by replacing what the view reads.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-205
  1. class_setupCreate the SQL test environment with a dependency list, here ZCMC_CORE_AGR
  2. setupclear_doubles, then insert_test_data with two agreement rows built in the test
  3. test methodThe CUT runs its normal SELECT; ABAP SQL reads the double, not the real table
  4. assertCheck the deposit and messages against the known test rows
  5. class_teardowndestroy the environment so later tests see real redirection removed
Lifecycle of an ABAP SQL test double in a test class.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-205
Tests against real dataNo change, no isolation: flaky, not repeatable
Test seamsSmall change to production code, good isolation, but invasive and temporary
SQL, CDS and function module doublesNo change to the code under test, strong isolation for data access
Interfaces plus injected doublesSome redesign up front, strong isolation and cleaner code
Ways to isolate a dependency, by design effort and isolation. Both top quadrants are good; the bottom-left is the one to leave.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-205

RAP business objects

When the code under test calls a RAP business object through EML, two framework options exist. The transactional buffer double replaces the BO's transactional buffer, so EML reads and modifications from the CUT work against test instances. The mock EML API lets the test configure what specific EML calls return. Both are created with a list of behavior definition dependencies. The advanced RAP course in this track applies them to draft and event behavior.

What would you do?

Kenji wants to test a new CDS view entity that sums open core deposits per fleet customer, including a filter that excludes agreements with status "closed". Which approach fits best?

Key points
  • Stubs return canned data, mocks also verify calls, fakes are simplified working versions.
  • Match the framework to the dependency: OO, SQL, CDS, function module, authority check, RAP.
  • SQL test doubles redirect ABAP SQL with no design change; CDS test doubles test logic inside a view.
  • Create environments in class_setup, reset in setup, destroy in class_teardown.

Check your understanding · not graded

Lesson check

  1. 1. Which class is the entry point of the ABAP SQL Test Double Framework?

  2. 2. What does the CDS Test Double Framework let you test?

  3. 3. For which dependency can CL_ABAP_TESTDOUBLE NOT create a double?

  4. 4. What distinguishes a mock from a stub?