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

Lesson 4 of 6

Testing draft, late numbering and side effects

11 min

Listen to this lesson

0:00 / 11:00

Draft is where most RAP test suites go quiet. A test that creates active instances never touches the draft tables, the Prepare action or state messages, yet that is exactly how Maria's team uses the agreement app every day. This lesson adds draft tests to Kenji's suite, then covers late numbering, which Contoso added so agreement numbers have no gaps from discarded drafts, and finally side effects, which ABAP Unit cannot see at all.

Draft in EML: the transactional key

In a draft-enabled BO, every instance key carries the draft indicator %is_draft, and the transactional key %tky combines %key with it. When a test creates an instance with %is_draft = if_abap_behv=>mk-on, the instance is a draft: a commit writes it to the draft table (ZCMC_CORE_AGR_D, ZCMC_CORE_AGI_D), not the active table. A test without that indicator creates active instances directly, which a Fiori user never does. Test both, on purpose.

Draft actionWhat it does (ABAP keyword documentation)What a test asserts
EditCopies an active instance into the draft tableA draft exists for agreement 100045; the active instance is unchanged
PrepareRuns the validations and determinations on save assigned to it in the BDEFDraft-only validation messages appear before activation
ActivateCopies the draft to the active table and clears the draft tableActive data updated; draft gone; failed is empty
DiscardClears the draft instanceNo draft row left; active data untouched
ResumeSets the lock again when a draft with an expired lock is changedBetter tested in CMQ with real sessions

The draft actions and what Contoso's draft tests check for each.

The states a draft test drives an agreement through. Each arrow is one EML statement and one assertion.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-304

A draft test, step by step

  1. Add the draft tables to the test doubles, so draft saves never reach the real ZCMC_CORE_AGR_D. Check on your release whether the CDS environment for the BO covers them or whether the SQL environment must list them.
  2. Create the agreement as a draft: %is_draft = if_abap_behv=>mk-on with ValidTo before ValidFrom, and commit. The draft is saved: drafts may be inconsistent.
  3. Execute Prepare on the draft's %tky. Assert that failed holds the agreement and reported has the validateDates message.
  4. Execute Activate. Assert it fails and the draft still exists. Maria's half-finished work must never be lost by a failed activation.
  5. Fix ValidTo with MODIFY ENTITIES on the draft, execute Activate again and commit. Assert the active agreement now exists with Status OPEN and the draft is gone.

Two details matter in draft validations. First, use %tky everywhere in handler code: a handler that reads with %key reads the active instance while the user edits the draft. A test that creates only active instances will never catch it, which is the strongest reason to have draft tests. Second, draft validations report state messages: the handler first clears the %state_area for its check and then adds a message with that state area, so a corrected draft does not keep showing the old error. A test that fixes the data and runs Prepare again should assert the old state message is gone.

Late numbering

After the first Mock, Dan asked for gapless agreement numbers for the audit trail. Kenji's team switched the root to late numbering: the RAP runtime calls the saver method adjust_numbers just before the save, and only then does the agreement get its final number. Until then, consumers work with a preliminary identifier, %pid, returned in mapped. With draft, the draft table needs the extra key field DRAFTUUID, as the keyword documentation notes.

With late numbering, the test converts the preliminary key to the final key inside COMMIT ENTITIES BEGIN ... END.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-304

The test cannot assert a real number range value, because it changes with every run. Kenji's team wraps the number range call in an interface, ZIF_CMC_AGR_NUMBER, injected into the saver, so the test supplies a double that returns 100045. The assertion then checks that the agreement was saved as 100045 and that CONVERT KEY maps the preliminary key to it. A separate test makes the double fail and asserts the save fails cleanly instead of saving an agreement without a number.

Side effects: test the metadata and the screen

Side effects are declared in the BDEF and turned into OData annotations; they have no ABAP implementation. ABAP Unit cannot see them. Contoso tests them in two cheap ways: an automated check that the service $metadata of ZUI_CMC_COREAGREEMENT_O4 still contains the side effects annotation for Quantity and DepositAmount, and a scripted UI check in CMQ where Maria changes Quantity from 10 to 12 and sees DepositAmount 540.00 without pressing Enter.

  1. Handler unit testvalidateDates with %tky on draft and active keys; state area cleared
  2. EML draft scenarioCreate draft, Prepare, failed Activate, fix, Activate
  3. Late numbering scenarioBEGIN, CONVERT KEY, END with a number double returning 100045
  4. Metadata checkSide effects annotation present in the service metadata
  5. CMQ UI checkQuantity 12 refreshes DepositAmount 540.00; resume after a lock timeout
Where each part of draft and numbering behavior gets its test.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-304

What goes wrong in testing

  • Active-only suites. All tests create active instances; the %key bug in a determination ships to CMQ.
  • Asserting real numbers. A test expecting the next number range value fails on the second run or in another client.
  • Validations not assigned to Prepare. Prepare runs only the validations listed for it in the BDEF; a test of Prepare exposes a forgotten assignment.
  • Expecting ABAP Unit to catch side effects. It never will; without a metadata or UI check they are untested.

What would you do?

Maria reports that after she fixes ValidTo in a draft, the error on ValidTo stays on screen until she activates. Kenji's handler unit tests for validateDates are all green. What test would have caught this?

Key points
  • Create drafts with %is_draft on and use %tky in handlers so draft and active instances are handled alike.
  • Prepare runs only the validations and determinations assigned to it; test that list.
  • Late numbering: assert keys inside COMMIT ENTITIES BEGIN ... CONVERT KEY ... END, with an injected number source.
  • Side effects are tested through metadata and the UI, never with ABAP Unit.

Check your understanding · not graded

Lesson check

  1. 1. What does %tky contain in a draft-enabled BO?

  2. 2. Which validations does the Prepare action run?

  3. 3. In which saver method does a late-numbered BO assign final keys?

  4. 4. Why does Contoso inject the number source in late numbering tests?

  5. 5. How are side effects of the agreement app tested?