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

Lesson 2 of 6

EML scenario tests: setup, COMMIT ENTITIES and teardown with ROLLBACK ENTITIES

11 min

Listen to this lesson

0:00 / 11:59

An EML scenario test drives the BO the way a consumer does: it creates or changes instances with MODIFY ENTITIES, runs actions, commits, and checks what was saved. SAP's RAP100 tutorial is the reference pattern, and Kenji's team copied its shape for ZCL_CMC_CORE_AGR_EML_TEST, a global test class in the agreement package. This lesson walks through it from the class definition to the last assertion.

The class skeleton

  1. Create a global class and add FOR TESTING RISK LEVEL HARMLESS DURATION SHORT to the definition. The tutorial places it after CREATE PUBLIC.
  2. Add the ABAP Doc test relation as the first line: "! @testing BDEF:ZR_CMC_CoreAgreement. Running ABAP Unit on the behavior definition now also runs this class; ADT lists it under Foreign Tests.
  3. Declare class data for the environments: one of type if_cds_test_environment and one of type if_osql_test_environment.
  4. In class_setup, create the CDS test environment for the BO's view entities with cl_cds_test_environment=>create_for_multiple_cds, and the SQL test environment with cl_osql_test_environment=>create for other tables the behavior reads with ABAP SQL.
  5. In setup, call clear_doubles on both environments and insert the test data each test needs.
  6. In teardown, call ROLLBACK ENTITIES so the next test starts with an empty transactional buffer.
  7. In class_teardown, call destroy on both environments.
The lifecycle of an EML scenario test class: doubles are created once, cleared before every test, and the buffer is rolled back after every test.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-304

What the doubles redirect

The CDS test environment replaces the data sources of the view entities you name, so reads of ZR_CMC_CoreAgreement and the managed save land in doubles of ZCMC_CORE_AGR and ZCMC_CORE_AGI, not in the real tables. Tables the handlers read with ABAP SQL go into the SQL environment. Contoso's validateCustomer reads the released customer view, so Kenji's team inserts a row for Great Lakes Fleet Services, customer 17100001, into its double; the test then passes on any client, freshly refreshed or not. Check on your release which entities each factory method doubles; the dependency list is the first thing to look at when a test writes to a real table.

DependencyEnvironmentTest data in setup
ZR_CMC_CoreAgreement and item viewCDS test environmentUsually none: the test creates agreements through EML
Released customer view read by validateCustomerCDS test environment (added to the doubled entities)17100001 Great Lakes Fleet Services; a second fleet customer
Draft tables ZCMC_CORE_AGR_D and ZCMC_CORE_AGI_DSQL test environmentNone; draft tests create drafts through EML (lesson 4)
Any Z table read with ABAP SQL in a handlerSQL test environmentOnly the rows that test needs

Kenji's dependency list for the scenario test class: if a dependency is missing here, the test touches real data.

A scenario test, step by step

The test method create_agreement_and_commit proves the main path: create an agreement with two items, let the determinations work, commit, and read the saved state.

  1. Create. MODIFY ENTITIES OF ZR_CMC_CoreAgreement ENTITY Agreement CREATE FIELDS ( Customer ValidFrom ValidTo ) WITH ... using %cid = 'AGR1', customer 17100001, valid for one year.
  2. Create by association. In the same statement, CREATE BY \_Item with %cid_ref = 'AGR1' adds two items for CMC-ALT-100 with deposits of 40.00 and 25.00 USD.
  3. Collect responses. MAPPED DATA(mapped) FAILED DATA(failed) REPORTED DATA(reported). Assert failed is initial and mapped-agreement has one entry.
  4. Commit. COMMIT ENTITIES RESPONSE OF ZR_CMC_CoreAgreement FAILED DATA(commit_failed) REPORTED DATA(commit_reported). Assert sy-subrc is 0 and both responses are initial.
  5. Read back. READ ENTITIES or a SELECT on the view. Assert Status is OPEN (setInitialStatus) and TotalDeposit is 65.00 (calcTotalDeposit).
  6. Leave nothing behind. The doubles hold the saved rows; teardown rolls back the buffer and setup clears the doubles before the next test.
Each assertion in the happy-path scenario test points to a different layer, so a red test tells Kenji where to look.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-304

Negative scenarios

The same class holds the negative paths, each in its own method: reject_valid_to_before_from creates an agreement with ValidTo before ValidFrom, commits, and asserts sy-subrc 4, the key in commit_failed-agreement, and a message in commit_reported-agreement with %element-ValidTo marked. close_open_agreement creates and commits an agreement, executes closeAgreement, commits again and reads Status CLOSED. reject_zero_deposit expects the item validation to fail. Keep one behavior per method and name it after the behavior, not after the method being called.

  1. ArrangeAgreement for 17100001 with ValidFrom 2026-11-01 and ValidTo 2026-10-01
  2. ActMODIFY ENTITIES, then COMMIT ENTITIES RESPONSE OF the BO
  3. Assert subrcsy-subrc is 4: early save phase rejected the buffer
  4. Assert failedThe agreement's %cid or key appears in commit_failed
  5. Assert reportedMessage bound to ValidTo; check the message class and number, not the text
The order of one negative scenario test for validateDates.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-304

What goes wrong in testing

  • Forgetting teardown. Without ROLLBACK ENTITIES, a failed commit leaves instances in the buffer and the next test inherits them. Order-dependent results follow.
  • Asserting text. A test that compares the message text breaks when a translator improves the wording. Compare message class, number and the marked element.
  • One test, five behaviors. A 200-line test that creates, closes, reopens and deletes fails without telling anyone which rule broke.
  • Committing in the wrong place. COMMIT ENTITIES is not allowed in behavior pools. It belongs in the test (the consumer), never in a handler.

What would you do?

Kenji's scenario test <code>reject_valid_to_before_from</code> passes on his machine but fails in the nightly run, where the agreement from a previous test is still in the buffer. What is the most likely fix?

Key points
  • The RAP100 pattern: test relation to the BDEF, CDS and SQL doubles in class_setup, clear in setup, ROLLBACK ENTITIES in teardown.
  • Assert after MODIFY ENTITIES and again after COMMIT ENTITIES, including sy-subrc.
  • Negative tests check failed keys and the marked element of the message, not the message text.
  • If a test writes to a real table, the dependency list is incomplete.

Check your understanding · not graded

Lesson check

  1. 1. What does the ABAP Doc comment "! @testing BDEF:ZR_CMC_CoreAgreement do?

  2. 2. Why does the scenario test class call ROLLBACK ENTITIES in teardown?

  3. 3. Where should the double for a table read with ABAP SQL in a handler be created?

  4. 4. A negative test should assert the message how?

  5. 5. Where may COMMIT ENTITIES be called?