Using the Rocket Software Unit Test Framework to facilitate smarter testing of Mainframe Subsystem programs
Introduction.
Since the late 1980s and the advent of SUnit and further through the 90s and the introduction of JUnit, the use of unit testing supported by a Unit Test Framework has grown rapidly and has become an industry standard approach for millions of software developers within the Distributed application development community.
The Great Divide.
For long standing historical reasons there is a perceived limitation associated with application code written for the IBM Mainframe Subsystems with regards to such testing methods. Predominantly written in COBOL and designed to run in the subsystems of CICS, IMS and JES, the concept of unit testing these application programs has traditionally been considered too much of a leap into the beyond.
At Rocket, we have long been advocates that these applications and the programming languages used to write them are perfectly at home in the modern world of software development. Rocket® Enterprise Developer (formerly part of Micro Focus) and Rocket® Visual COBOL® (formerly part of Micro Focus) have provided the Unit Test Framework since the release of version 2.3 in 2015.
Prior to the 9.0 release of Enterprise Developer, a COBOL program that contains both business logic and "EXEC SQL" and/or "EXEC CICS" statements would not have been an ideal candidate for a unit test. So, the MFUnit functionality has been evolved further to include support for the ‘ignore’ and mock of EXEC CICS and SQL statements, making it simpler than ever to cross the ‘Great Divide’ and bring smarter testing methodologies to mainframe subsystem programs. In the latest release, version 10.0, some initial support has been added for “EXEC DLI” statements.
Unsurprisingly, due to this ‘Great Divide’, there is currently little written on the value of using Unit Testing for mainframe application code but there are many articles such as this, which detail the value of unit testing. If you perceive a ‘Specific piece of software’ as a COBOL Paragraph or Section, then all the reasons discussed apply equally to mainframe code.
How can it be used?
Before delving more into the details, it is important to set some context around the use of these new EXEC SQL/CICS ignore & mocking features.
Its purpose is to "reveal" the COBOL logic in an EXEC based program so it can be tested and should not be considered as a method to test CICS and/or SQL based applications as a whole.
How does it work?
The Unit Test Seam pre-processor (MFUPP) has been enhanced to aid the creation of self-contained unit tests that contain "EXEC CICS", "EXEC SQL" or "EXEC DLI" statements.
These EXEC statements can be removed or mocked depending on the requirement of the test case.
The Unit Test Runner has also been enhanced to aid the development of these styles of unit tests by the addition of new code generation options available via the command line interface.
Figure 1 - Unit Test Seam Pre-Processor
The Unit Test Seam pre-processor (MFUPP) allows code to be manipulated without changing the original source code with the sole intent of creating a unit test.
It has the ability to insert copybooks in various divisions, remove certain EXEC statements and insert mocking callbacks statements.
Producing Unit Tests.
Considering a program that contains embedded SQL statements, it can now be made into a unit test by one or both of the following mechanisms:
- Ignoring the EXEC SQL statement(s)
- Mocking the EXEC SQL statement(s)
It might seem strange to have a seam pre-processor feature that removes code but it is really useful when trying to create a unit test of a section or paragraph that includes embedded SQL
If the COBOL section or paragraph that is to be tested has a single "EXEC SQL" statement, then it is an ideal candidate for using the seam pre-processor's removal feature, as the values updated by "EXEC SQL" statement can be included in the unit test case without the need for any mocking.
Figure 2 - COBOL paragraph with embedded SQL statement
Imagine a COBOL program that contains an EXEC SQL FETCH statement to get a new row of data and then does some calculations (business logic) on it.
Without the use of the seam pre-processor there would have to be a deployed/usable database available for testing.
Next, within the test case a cursor would need to have opened ready for the fetch before the paragraph can be tested.
This is a lot of overhead and setup for testing a section or paragraph. Figure 2 - COBOL paragraph with embedded SQL statement
Figure 3 - Unit Test ignoring the SQL statement
Using the Seam pre-processor self-contained unit testing feature, a test case can be created that will be embedded in the program.
This is achieved by writing the test case in the filename prefixed filename MFUPD_. This is done to ensure we can access all the fields in the program and do a perform 50-FETCH-UPDATE paragraph.
Figure 4 - Unit Test mocking the SQL statement.
The previous example of ScanEmployeeTable has now evolved
It is now impossible to fake up the values from the SQL FETCH by simply removing the EXEC SQL statement because the first thing the "test" paragraph does is to initialize the EMP-TABLE, thus throwing away any variable’s setup.
So now mocking is required.
As with the program mocking support, provided prior to this release, an entry-point needs to be registered to act as the controller. This is done in the metadata entry-point and the name of symbol is placed in the MFU-MD-EXEC-CONTROLLER field.
Next, we need to declare an entry-point to handle mock SQL statement, for this example, this is where the required move statements to mock this FETCH statement will be set up.
For this simple example all the parameters are not declared, as we are not using them.
The Unit Test Seam pre-processor support for “EXEC CICS” statements is designed to feel familiar as its features are symmetrical to the ones provided for “EXEC SQL” statements.
Ignoring “EXEC CICS” and "EXEC DLI" statements is as simple as it is for “EXEC SQL” statements and mocking uses the same callback mechanism.
Figure 5 - Examples of ignoring EXEC DLI statements.
Helping to write Unit Tests.
All modernization requires investment if the full value is to be realized but any test tooling should assist the developer in producing test cases as much as possible. To this end, a Code Snippet generation feature is included in the MFUnit framework to create code to help mock the EXEC statement with the program under test.
Figure 5 - Examples of unique ID for mocked statements.
By default, the snippet generator creates a mock snippet for each EXEC statement.
Each mocked statement is given a unique ID, this identifier can be changed by instrumenting the code before the EXEC statement with a comment.
This allows the snippet generator to create cleaner looking code by restricting the code generation to just these custom identifiers.
Figure 6 - Help when mocked program uses COMMAREA
A CICS program may use a COMMAREA and is something the normal CICS ECM would handle. However, a test case may require this to be initialized and available for population by a test case. The Seam pre-processor injects two extra paragraphs that can be used.
The section MFUPP--INIT-CICS allocates the COMMAREA and places the size in EIBCALEN.
When the use of the COMMAREA is no longer required, the section MFUPP--END-CICS can be used.
Summary
The Unit Test Framework, available with Enterprise Developer, has two new features in the Seam pre-processor.
The first, removal or ignoring of the `EXEC SQL`, `EXEC CICS` and "EXEC DLI" which reveal the logic to be tested without needing any mocking.
The second, EXEC statement mocking support allows simplified alternatives to EXEC statements that provide the program with just-enough data to allow it to be tested.
With this additional support, mainframe subsystem programs can be tested quickly as the subsystem itself is not required, nor the provision of any data. In fact, the only thing you need to test the code is the code itself.
To see some of this in action, please watch this video.