Testing COBOL

COBOL Check lets you write unit tests in a COBOL-like DSL; it merges tests into a copy of the program and runs it (works with GnuCOBOL locally and on z/OS).

33.1 Levels of testing

Unit (paragraph/program) COBOL Check (Open Mainframe Project), IBM zUnit (IBM Developer for z/OS / IBM Test Accelerator for Z), Rocket Visual COBOL unit testing (MFUnit)

Test JCL streams, CICS test regions, Galasa (open-source integration test framework for z/OS)

Compare outputs of old and new versions (diff; SuperC/ISRSUPC on z/OS); record/replay tools

Repeatable batch runs with production-like volumes

33.2 COBOL Check

COBOL Check lets you write unit tests in a COBOL-like DSL; it merges tests into a copy of the program and runs it (works with GnuCOBOL locally and on z/OS).

Run it with the cobolcheck launcher (e.g., cobolcheck -p TAXCALC), which generates the test program, compiles it, and reports pass/fail. MOCK PARAGRAPH name ... END-MOCK (also for SECTIONs and CALLs) replaces dependencies such as I/O or rate lookups with test behavior.

TestSuite "Tax calculation paragraph 2200-CALC-TAX"

           TestCase "Standard rate applies below threshold"
               MOVE 1000.00 TO WS-GROSS
               MOVE "S" TO WS-TAX-CODE
               PERFORM 2200-CALC-TAX
               EXPECT WS-TAX TO BE 215.00

           TestCase "Exempt customers pay no tax"
               MOVE 1000.00 TO WS-GROSS
               MOVE "E" TO WS-TAX-CODE
               PERFORM 2200-CALC-TAX
               EXPECT WS-TAX TO BE 0

33.3 Designing testable COBOL

Keep business rules in small paragraphs or subprograms with clear inputs/outputs, and isolate I/O in dedicated paragraphs (8000-READ-..., 8100-WRITE-...) so tests can mock them.

Put magic numbers in 88-levels and tables; test boundary values (zero, maximum PICTURE value, negative, empty file, single record, duplicate keys).

Run unit tests automatically in the CI pipeline (Chapter 41).

🧪 Part III Exercises

Split your Part II customer report into a main program and two subprograms (validation and formatting); compile once statically and once with dynamic loading.

Demonstrate the difference between BY REFERENCE, BY CONTENT, and BY VALUE with a subprogram that modifies all three parameters.

Write a nested program structure with a GLOBAL error-count field and a COMMON logging routine called from two sibling programs.

Implement recursive Fibonacci and Towers of Hanoi with RECURSIVE and LOCAL-STORAGE; print the moves for 4 disks.

Create an address copybook and use COPY ... REPLACING to build billing, shipping, and mailing address groups in one record.

Introduce a deliberate subscript-out-of-range bug and a non-numeric data bug; detect them with GnuCOBOL -debug (and, if you have z/OS access, SSRANGE and NUMCHECK).

Generate JSON for an array of three customers (a table with OCCURS) and inspect how COBOL names map to JSON keys; customize the names with NAME OF.

Write an XML PARSE program (IBM or Visual COBOL) that totals the <amount> elements of an invoice document.

Write a user-defined function VALID-ISBN that returns 1 or 0 for a 13-digit ISBN check digit, and call it from a test driver.

Install COBOL Check and write at least five test cases (including one mock) for the tax calculation paragraph of exercise 1.