이 글에서 다룰 것
ABAP Unit 테스트를 작성했더라도 어느 코드 경로가 실제로 검증되고 있는지 모르면, 테스트가 통과해도 안심할 수 없습니다. SCOV(Coverage Analyzer)는 ABAP Unit 실행 시 어떤 라인과 분기가 호출되었는지 측정해주는 도구입니다. 이 글에서는 FOR TESTING 클래스 작성부터 SCOV 결과 해석, Line/Branch 커버리지 차이까지 실무 흐름 그대로 살펴봅니다.
- FOR TESTING 클래스/메서드 선언과 cl_abap_unit_assert 단정문 사용
- ADT(Eclipse) 또는 SE80에서 ABAP Unit 실행과 결과 확인
- SCOV 트랜잭션으로 패키지·클래스 단위 커버리지 조회
- Line Coverage와 Branch Coverage의 차이, 미커버 경로 식별
- 커버리지 임계값 기준으로 테스트 보강 전략 수립
이 글을 보기 전에
ABAP OO 클래스 작성과 메서드 호출 흐름을 이해하고 있어야 합니다. SE24/SE80 또는 ADT에서 글로벌 클래스를 만들어본 경험, 그리고 IF/CASE/LOOP 같은 기본 제어문에 익숙해야 합니다. ABAP Unit 자체를 처음 본다면 cl_abap_unit_assert의 assert_equals 정도만 미리 확인하면 충분합니다.
환경 / 버전 / 준비물
- 시스템: SAP NetWeaver 7.40 이상 권장 (7.52 / S/4HANA 2022 기준 검증)
- 도구: SAP GUI 750 이상 또는 ADT(Eclipse) 최신 버전
- 권한: S_DEVELOP(개발 권한), 트랜잭션 SCOV / SE24 / SE80 실행 권한
- 전제: 테스트 대상 클래스가 활성화되어 있어야 하며, 패키지에 변경 가능 모드 접근 가능
- 참고: ADT에서는 Run As → ABAP Unit Test with Coverage 메뉴로 동일 데이터 시각화
핵심 개념
코드 커버리지는 테스트가 코드의 어디까지 실제로 실행시켰는가를 정량화한 지표입니다. SCOV는 세 가지 관점에서 결과를 제공합니다.
- Statement(Line) Coverage: 각 명령문이 한 번이라도 실행되었는지 측정. 직관적이지만 IF 참/거짓 양쪽을 보장하지는 않습니다.
- Branch Coverage: IF, CASE, WHILE, CHECK 분기점에서 가능한 경로가 모두 실행되었는지 확인. 라인 100%여도 Branch 50%인 함정이 여기서 드러납니다.
- Procedure Coverage: 메서드/폼/함수모듈 단위 호출 여부. 죽은 코드(dead code) 후보 식별에 유용합니다.
비유하자면 Line은 도로 차로의 통행량 점검이고, Branch는 교차로마다 좌회전·우회전·직진을 다 시도해봤는지의 점검입니다. 한 차로는 지나갔지만 좌회전(else 분기)을 한 번도 안 했다면 그 경로의 결함은 숨겨집니다.
실전 코드 3단계
1단계 — ABAP Unit 테스트 작성
간단한 할인 계산 클래스 zcl_discount_calc에 FOR TESTING 로컬 테스트 클래스를 붙입니다.
CLASS zcl_discount_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS calculate
IMPORTING iv_amount TYPE p LENGTH 10 DECIMALS 2
iv_is_member TYPE abap_bool
RETURNING VALUE(rv_price) TYPE p LENGTH 10 DECIMALS 2.
ENDCLASS.
CLASS zcl_discount_calc IMPLEMENTATION.
METHOD calculate.
IF iv_amount <= 0.
rv_price = 0. RETURN.
ENDIF.
IF iv_is_member = abap_true.
rv_price = iv_amount * '0.9'.
ELSE.
rv_price = iv_amount.
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS ltcl_discount DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO zcl_discount_calc.
METHODS: setup, member_gets_10pct FOR TESTING.
ENDCLASS.
CLASS ltcl_discount IMPLEMENTATION.
METHOD setup. mo_cut = NEW #( ). ENDMETHOD.
METHOD member_gets_10pct.
DATA(lv) = mo_cut->calculate( iv_amount = 100 iv_is_member = abap_true ).
cl_abap_unit_assert=>assert_equals( act = lv exp = CONV #( '90.00' ) ).
ENDMETHOD.
ENDCLASS.
ADT에서 Ctrl+Shift+F10, 또는 SE80에서 Unit Tests 실행. 이 시점에서는 회원 케이스 하나만 검증됩니다.
2단계 — SCOV 트랜잭션으로 커버리지 조회
ADT에서는 클래스 우클릭 → Run As → ABAP Unit Test with Coverage를 선택합니다. SAP GUI에서는 Unit Test 실행 직후 트랜잭션 SCOV를 실행하고 패키지/클래스를 입력한 뒤 Execute합니다.
" SCOV 결과 프로그래밍 방식 조회
DATA: lo_api TYPE REF TO cl_scov_api,
lt_coverage TYPE scov_t_pkg_result.
TRY.
lo_api = cl_scov_api=>create( ).
lo_api->get_aggregated_results(
EXPORTING iv_package = 'ZFIN_DISCOUNT'
IMPORTING et_results = lt_coverage ).
LOOP AT lt_coverage ASSIGNING FIELD-SYMBOL(<ls>).
IF <ls>-branch_coverage_pct < 80.
MESSAGE |Branch low: { <ls>-object_name } { <ls>-branch_coverage_pct }%| TYPE 'W'.
ENDIF.
ENDLOOP.
CATCH cx_scov_execution_error INTO DATA(lx_err).
MESSAGE lx_err->get_text( ) TYPE 'E'.
ENDTRY.
이 단계에서 Statement는 약 75%, Branch는 50% 수준입니다. 비회원 분기와 0 이하 금액 분기가 한 번도 실행되지 않았기 때문입니다.
3단계 — 분기 보강으로 Branch Coverage 달성
누락 경로별 테스트 메서드를 추가합니다.
CLASS ltcl_discount DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO zcl_discount_calc.
METHODS:
setup,
member_gets_10pct FOR TESTING,
non_member_pays_full FOR TESTING,
zero_amount_returns_0 FOR TESTING,
negative_amount_safe FOR TESTING.
ENDCLASS.
CLASS ltcl_discount IMPLEMENTATION.
METHOD setup. mo_cut = NEW #( ). ENDMETHOD.
METHOD member_gets_10pct.
cl_abap_unit_assert=>assert_equals(
act = mo_cut->calculate( iv_amount = 200 iv_is_member = abap_true )
exp = CONV #( '180.00' ) ).
ENDMETHOD.
METHOD non_member_pays_full.
cl_abap_unit_assert=>assert_equals(
act = mo_cut->calculate( iv_amount = 200 iv_is_member = abap_false )
exp = CONV #( '200.00' ) ).
ENDMETHOD.
METHOD zero_amount_returns_0.
cl_abap_unit_assert=>assert_equals(
act = mo_cut->calculate( iv_amount = 0 iv_is_member = abap_true )
exp = CONV #( '0.00' ) ).
ENDMETHOD.
METHOD negative_amount_safe.
cl_abap_unit_assert=>assert_equals(
act = mo_cut->calculate( iv_amount = -50 iv_is_member = abap_false )
exp = CONV #( '0.00' ) ).
ENDMETHOD.
ENDCLASS.
네 개의 테스트가 모두 통과하면 SCOV에서 Statement / Branch / Procedure 모두 100%에 근접합니다.
흔한 실수 / 트러블슈팅
Q1. SCOV를 열어도 데이터가 비어 있습니다.
ABAP Unit을 커버리지 모드로 한 번도 실행하지 않은 상태에서 SCOV를 열면 빈 화면입니다. ADT의 ABAP Unit Test with Coverage 실행 직후 다시 시도하세요.
Q2. Line Coverage는 100%인데 Branch가 60%입니다.
IF 한 줄이 실행되었다고 해서 참/거짓 분기 모두 실행된 것이 아닙니다. true 케이스만 테스트하면 false 분기는 미커버 상태로 남습니다.
Q3. 측정 대상 클래스가 SCOV에 안 보입니다.
패키지 필터 확인, 클래스가 활성(active) 상태인지 점검하세요. 글로벌 클래스가 FOR TESTING으로 마킹된 경우 SCOV 측정 대상에서 제외됩니다.
Q4. 운영 시스템에서 SCOV를 돌려도 되나요?
원칙적으로 운영계에서는 단위테스트와 커버리지 측정을 수행하지 않는 것이 권장됩니다. 개발/품질(DEV/QAS) 시스템에서만 실행하세요.
다음 단계 / 관련 주제
- ATC(ABAP Test Cockpit) 통합: 정적 검사와 커버리지를 함께 게이트로 사용
- Test Doubles Framework: cl_abap_testdouble로 의존성을 격리해 분기 테스트 작성
- gCTS + Piper 파이프라인: 커버리지 임계값을 빌드 실패 조건으로 자동화
- BTP ABAP Environment Coverage View: Steampunk 환경의 ADT 기반 커버리지 시각화
참고 자료
핵심 한 줄
테스트가 통과한다는 사실보다, 테스트가 어떤 분기를 실제로 지나갔는지를 SCOV로 확인하는 습관이 품질의 분기점이 됩니다.
댓글 0
아직 댓글이 없습니다.