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

Lesson 6 of 6

Refactoring safely: tests first

11 min

Listen to this lesson

0:00 / 9:23

Everything in this course changes code that already works. That is refactoring: changing structure without changing behavior. The previous lessons showed three places where "only syntax" changes behavior: missing rows in table expressions, initialized fields in CORRESPONDING, and formatting in string templates. This lesson puts the safety net first: characterization tests that pin current behavior, small steps, SAP's tools that help, and the evidence Priya needs to accept refactored code.

Characterization tests

A characterization test records what the code does today, right or wrong. You run the code with fixed inputs, capture the output, and assert exactly that output. Then you refactor. If the test stays green, behavior did not change. If it turns red, you either made a mistake or found behavior that someone must decide on. Michael Feathers coined the term; the Academy's legacy modernization course uses it at the program level. Here it is applied to one method at a time.

The refactoring loop: pin, change one thing, run, keep or revert. Small steps keep a red test easy to explain.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-206

Making legacy code testable

ObstacleClassic symptomSmallest fix
Database reads inside the logicSELECT in the middle of a FORM routineABAP SQL test double framework; no code change needed
Report with selection screen and WRITELogic tangled with outputExtract the logic into a local or global class method; test the method
Global data everywhereHeader lines and TABLES parametersPass data as parameters to the extracted method
Current date or usersy-datum in the logicInject the date (in ABAP Cloud, read it via cl_abap_context_info or XCO behind an interface)
Function module callsCALL FUNCTION with side effectsFunction module test double framework, or wrap it

Common obstacles in Contoso's legacy code and the smallest change that makes the logic testable.

Walkthrough: refactoring ZCMC_CORE_RET_LIST

  1. Scope. A change request asks for a new column in the core return list. The object will be touched, so the team modernizes the parts it changes.
  2. Extract. Kenji moves the calculation from the report's FORM routines into a method of ZCL_CMC_CORE_DEPOSIT, using ADT's extract method quick fix, without changing logic.
  3. Pin. He writes characterization tests with SQL test doubles: Great Lakes Fleet Services (17100001) with two OPEN agreements, a CLOSED agreement, a missing deposit rate, and an empty result.
  4. Refactor in steps. Inline declarations; then the select; then the lookup with DEFAULT 45 (an intended change agreed with Maria); then the total with REDUCE. Tests run after each step.
  5. Clean up. SAP's open-source ABAP cleaner applies many modern-syntax and Clean ABAP rules automatically; Kenji runs it on the changed method and reviews the diff like any other change.
  6. Check. ATC on the changed objects, coverage of the extracted method, then release.
The refactoring of one legacy report, from extraction to the evidence Priya reviews.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-206

Tools that help, and their limits

  • ADT quick fixes (Ctrl+1) extract methods, declare variables and convert some statements. They are mechanical; tests still decide.
  • ABAP cleaner (SAP, open source) applies modern syntax and formatting rules in bulk. Configure its profile with the team, and never run it on code you are not otherwise changing.
  • ATC with the ABAP Cloud readiness checks shows statements the restricted language version rejects.
  • Clean ABAP (SAP's style guide on GitHub) is the reference for naming and readability arguments in review.
Leave aloneRarely changed, low risk: classic syntax is fine
Modernize when touchedOften changed, low risk: refactor with each change
Pin firstRarely changed, high risk: characterization tests before any change
PriorityOften changed, high risk: tests, then refactor in small steps
Where Contoso spends refactoring effort.
The Sign-Off Table · thesignofftable.com/academy/sap-abp-206

Reviewing a refactoring diff

  • Read the tests first. Did they exist before the change, and do they assert outputs, including edge cases such as an empty table and a missing row?
  • Look for behavior-changing constructs. Table expressions without OPTIONAL or DEFAULT, CORRESPONDING without BASE, string templates replacing WRITE ... TO, REDUCE with an untyped INIT.
  • Check the select. Same rows, same order, same fields as before, or a recorded reason why not.
  • Check the list of intended changes. Each one has a test and a named person who confirmed it.

What goes wrong

  • Refactoring and feature in one step. When a test turns red, nobody knows whether the new column or the refactoring caused it. Separate the steps, even within one transport.
  • Tests written after the refactoring. They pin the new behavior, including any regression.
  • Silent intended changes. A fixed defect is still a change; key users must know.
  • Tool-only refactoring. A bulk run of a cleanup tool across a package that nobody tests.

What would you do?

A developer on Kenji's team proposes running ABAP cleaner across the whole ZCMC_SD package to modernize syntax in one transport, since "it only changes syntax". What should Kenji say?

Key points
  • Pin current behavior with characterization tests before changing code.
  • Refactor in small steps and run the tests after each one.
  • Extract logic out of reports so it can be tested; use SQL and function module test doubles.
  • ABAP cleaner, quick fixes and ATC help; tests and review decide.

Check your understanding · not graded

Lesson check

  1. 1. What does a characterization test assert?

  2. 2. Why separate a refactoring step from a feature change?

  3. 3. What is ABAP cleaner?

  4. 4. Which legacy code should Contoso leave in classic syntax?

  5. 5. A refactoring fixes an old defect. Who must confirm it?