MainframeMaster

COBOL Class Tests

Class testing in COBOL is essential for ensuring that object-oriented code works correctly and reliably. By creating comprehensive test suites, developers can verify that classes behave as expected, catch bugs early, and maintain code quality throughout the development lifecycle.

Understanding Class Testing

Class testing focuses on verifying the behavior of individual classes in isolation. This includes testing method functionality, property management, inheritance relationships, and edge cases. Effective class testing helps identify issues before they impact the larger system and provides confidence when making code changes.

Basic Test Structure

1. Test Class Definition

A test class in COBOL is designed specifically to test another class. It creates instances of the class under test, calls its methods with various inputs, and verifies the results. The test class should be separate from the production code to maintain clear separation of concerns.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
IDENTIFICATION DIVISION. PROGRAM-ID. CUSTOMER-CLASS-TEST. *> This program tests the CUSTOMER-CLASS functionality *> It verifies that all methods work correctly with various inputs DATA DIVISION. WORKING-STORAGE SECTION. *> Test data and result tracking 01 TEST-RESULTS. 05 TOTAL-TESTS PIC 9(3) VALUE 0. 05 PASSED-TESTS PIC 9(3) VALUE 0. 05 FAILED-TESTS PIC 9(3) VALUE 0. 05 TEST-STATUS PIC X(1). 88 TEST-PASSED VALUE 'P'. 88 TEST-FAILED VALUE 'F'. *> Test data for customer operations 01 TEST-CUSTOMER-DATA. 05 TEST-CUSTOMER-ID PIC 9(8) VALUE 12345678. 05 TEST-CUSTOMER-NAME PIC X(50) VALUE 'John Smith'. 05 TEST-CUSTOMER-EMAIL PIC X(100) VALUE 'john.smith@email.com'. *> Object reference for the class under test 01 CUSTOMER-OBJECT USAGE OBJECT REFERENCE. PROCEDURE DIVISION. MAIN-TEST-LOGIC. DISPLAY 'Starting Customer Class Tests' PERFORM INITIALIZE-TEST-ENVIRONMENT PERFORM RUN-ALL-TESTS PERFORM DISPLAY-TEST-RESULTS STOP RUN.

The test class begins with a clear identification of its purpose. The WORKING-STORAGE SECTION contains test data, result tracking variables, and an object reference that will hold the instance of the class being tested. The main procedure orchestrates the entire testing process, from setup through execution to reporting.

2. Test Initialization

Test initialization sets up the testing environment by creating objects, preparing test data, and establishing baseline conditions. This ensures that each test starts from a known, clean state, making test results predictable and reliable.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
INITIALIZE-TEST-ENVIRONMENT. *> Create a new instance of the customer class INVOKE CUSTOMER-CLASS "NEW" RETURNING CUSTOMER-OBJECT *> Verify the object was created successfully IF CUSTOMER-OBJECT = NULL DISPLAY 'ERROR: Failed to create customer object' MOVE 999 TO RETURN-CODE STOP RUN END-IF *> Initialize test counters MOVE 0 TO TOTAL-TESTS MOVE 0 TO PASSED-TESTS MOVE 0 TO FAILED-TESTS *> Display test environment information DISPLAY 'Test environment initialized successfully' DISPLAY 'Customer object created: ' CUSTOMER-OBJECT. RUN-ALL-TESTS. *> Execute all test cases PERFORM TEST-SET-CUSTOMER-DATA PERFORM TEST-GET-CUSTOMER-BALANCE PERFORM TEST-UPDATE-BALANCE PERFORM TEST-VALIDATE-CUSTOMER-DATA PERFORM TEST-INVALID-INPUTS.

The initialization process creates a fresh instance of the class under test using the INVOKE statement with the "NEW" method. This is crucial because it ensures each test starts with a clean object state. The code also includes error checking to verify that object creation succeeded, which prevents tests from running with invalid objects.

Individual Test Cases

1. Testing Method Functionality

Individual test cases focus on specific methods or behaviors. Each test case should have a clear purpose, use known input data, and verify expected outputs. Good test cases cover both normal operations and edge cases to ensure robust behavior.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
TEST-SET-CUSTOMER-DATA. *> Test the SET-CUSTOMER-DATA method with valid input ADD 1 TO TOTAL-TESTS DISPLAY 'Testing SET-CUSTOMER-DATA method...' *> Call the method with test data INVOKE CUSTOMER-OBJECT "SET-CUSTOMER-DATA" USING TEST-CUSTOMER-ID TEST-CUSTOMER-NAME TEST-CUSTOMER-EMAIL *> Verify the data was set correctly by calling a getter method INVOKE CUSTOMER-OBJECT "GET-CUSTOMER-ID" RETURNING RETRIEVED-CUSTOMER-ID *> Compare retrieved value with expected value IF RETRIEVED-CUSTOMER-ID = TEST-CUSTOMER-ID ADD 1 TO PASSED-TESTS SET TEST-PASSED TO TRUE DISPLAY 'PASS: Customer ID set correctly' ELSE ADD 1 TO FAILED-TESTS SET TEST-FAILED TO TRUE DISPLAY 'FAIL: Customer ID not set correctly' DISPLAY 'Expected: ' TEST-CUSTOMER-ID DISPLAY 'Actual: ' RETRIEVED-CUSTOMER-ID END-IF. TEST-GET-CUSTOMER-BALANCE. *> Test the GET-CUSTOMER-BALANCE method ADD 1 TO TOTAL-TESTS DISPLAY 'Testing GET-CUSTOMER-BALANCE method...' *> Set an initial balance through a method call INVOKE CUSTOMER-OBJECT "UPDATE-BALANCE" USING INITIAL-BALANCE-AMOUNT DEPOSIT-TYPE RETURNING UPDATE-SUCCESS *> Retrieve the balance and verify it matches INVOKE CUSTOMER-OBJECT "GET-CUSTOMER-BALANCE" RETURNING RETRIEVED-BALANCE IF RETRIEVED-BALANCE = INITIAL-BALANCE-AMOUNT ADD 1 TO PASSED-TESTS SET TEST-PASSED TO TRUE DISPLAY 'PASS: Balance retrieved correctly' ELSE ADD 1 TO FAILED-TESTS SET TEST-FAILED TO TRUE DISPLAY 'FAIL: Balance retrieval failed' END-IF.

Each test case follows a consistent pattern: increment the test counter, call the method being tested, verify the results, and update the pass/fail counters. The verification step is crucial - it compares actual results with expected results and provides clear feedback about whether the test passed or failed. This approach makes it easy to identify which specific functionality is working or broken.

2. Testing Edge Cases

Edge cases test the boundaries and limits of class behavior. These tests verify that the class handles unusual inputs gracefully, such as invalid data, boundary values, or error conditions. Testing edge cases helps ensure robust, production-ready code.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
TEST-INVALID-INPUTS. *> Test how the class handles invalid input data ADD 1 TO TOTAL-TESTS DISPLAY 'Testing invalid input handling...' *> Test with zero customer ID (should be invalid) INVOKE CUSTOMER-OBJECT "SET-CUSTOMER-DATA" USING ZERO-CUSTOMER-ID TEST-CUSTOMER-NAME TEST-CUSTOMER-EMAIL *> Verify that invalid data is rejected INVOKE CUSTOMER-OBJECT "VALIDATE-CUSTOMER-DATA" RETURNING VALIDATION-RESULT ERROR-MESSAGE IF VALIDATION-RESULT = 'N' ADD 1 TO PASSED-TESTS SET TEST-PASSED TO TRUE DISPLAY 'PASS: Invalid customer ID rejected' DISPLAY 'Error message: ' ERROR-MESSAGE ELSE ADD 1 TO FAILED-TESTS SET TEST-FAILED TO TRUE DISPLAY 'FAIL: Invalid customer ID was accepted' END-IF. TEST-BOUNDARY-VALUES. *> Test boundary conditions for numeric values ADD 1 TO TOTAL-TESTS DISPLAY 'Testing boundary values...' *> Test maximum allowed balance MOVE 9999999999.99 TO MAX-BALANCE-AMOUNT INVOKE CUSTOMER-OBJECT "UPDATE-BALANCE" USING MAX-BALANCE-AMOUNT DEPOSIT-TYPE RETURNING UPDATE-SUCCESS IF UPDATE-SUCCESS = 'Y' ADD 1 TO PASSED-TESTS SET TEST-PASSED TO TRUE DISPLAY 'PASS: Maximum balance accepted' ELSE ADD 1 TO FAILED-TESTS SET TEST-FAILED TO TRUE DISPLAY 'FAIL: Maximum balance rejected' END-IF. TEST-NEGATIVE-VALUES. *> Test handling of negative values ADD 1 TO TOTAL-TESTS DISPLAY 'Testing negative value handling...' *> Try to withdraw more than available balance MOVE 1000000.00 TO EXCESSIVE-WITHDRAWAL INVOKE CUSTOMER-OBJECT "UPDATE-BALANCE" USING EXCESSIVE-WITHDRAWAL WITHDRAWAL-TYPE RETURNING UPDATE-SUCCESS IF UPDATE-SUCCESS = 'N' ADD 1 TO PASSED-TESTS SET TEST-PASSED TO TRUE DISPLAY 'PASS: Excessive withdrawal properly rejected' ELSE ADD 1 TO FAILED-TESTS SET TEST-FAILED TO TRUE DISPLAY 'FAIL: Excessive withdrawal was allowed' END-IF.

Edge case testing is crucial for ensuring that classes handle unusual situations gracefully. These tests verify that the class validates input data properly, rejects invalid values, and provides appropriate error messages. By testing boundary conditions and error scenarios, we ensure that the class behaves predictably in all situations.

Testing Inheritance

1. Testing Inherited Methods

When testing classes that inherit from other classes, it's important to verify that inherited methods work correctly in the subclass context. This includes testing that inherited properties are accessible and that inherited methods produce expected results.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
TEST-INHERITED-METHODS. *> Test methods inherited from parent class ADD 1 TO TOTAL-TESTS DISPLAY 'Testing inherited methods...' *> Create an instance of the subclass INVOKE PREMIUM-CUSTOMER-CLASS "NEW" RETURNING PREMIUM-OBJECT *> Test inherited method from parent class INVOKE PREMIUM-OBJECT "SET-CUSTOMER-DATA" USING TEST-CUSTOMER-ID TEST-CUSTOMER-NAME TEST-CUSTOMER-EMAIL *> Verify inherited method works in subclass INVOKE PREMIUM-OBJECT "GET-CUSTOMER-ID" RETURNING RETRIEVED-ID IF RETRIEVED-ID = TEST-CUSTOMER-ID ADD 1 TO PASSED-TESTS SET TEST-PASSED TO TRUE DISPLAY 'PASS: Inherited method works in subclass' ELSE ADD 1 TO FAILED-TESTS SET TEST-FAILED TO TRUE DISPLAY 'FAIL: Inherited method failed in subclass' END-IF. TEST-METHOD-OVERRIDING. *> Test that overridden methods work correctly ADD 1 TO TOTAL-TESTS DISPLAY 'Testing method overriding...' *> Set up premium membership INVOKE PREMIUM-OBJECT "SET-PREMIUM-MEMBERSHIP" USING 'PLATINUM' 15.00 *> Test overridden method with premium discount INVOKE PREMIUM-OBJECT "CALCULATE-TOTAL-CHARGES" USING TRANSACTION-COUNT AVERAGE-TRANSACTION RETURNING PREMIUM-TOTAL *> Calculate expected total with premium discount COMPUTE EXPECTED-PREMIUM-TOTAL = (TRANSACTION-COUNT * AVERAGE-TRANSACTION) * 0.85 IF PREMIUM-TOTAL = EXPECTED-PREMIUM-TOTAL ADD 1 TO PASSED-TESTS SET TEST-PASSED TO TRUE DISPLAY 'PASS: Method overriding works correctly' ELSE ADD 1 TO FAILED-TESTS SET TEST-FAILED TO TRUE DISPLAY 'FAIL: Method overriding failed' END-IF.

Inheritance testing verifies that the subclass correctly inherits functionality from its parent class while also testing that overridden methods provide the expected specialized behavior. This ensures that the inheritance hierarchy works correctly and that polymorphic behavior functions as intended.

Test Assertions and Validation

1. Assertion Framework

Assertions are statements that verify expected conditions in tests. A good assertion framework provides clear, readable ways to check test results and generates meaningful error messages when tests fail. This makes debugging easier and test results more informative.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
ASSERT-EQUALS. *> Generic assertion to check if two values are equal *> Parameters: expected-value, actual-value, test-description DATA DIVISION. LINKAGE SECTION. 01 EXPECTED-VALUE PIC X(100). 01 ACTUAL-VALUE PIC X(100). 01 TEST-DESCRIPTION PIC X(50). PROCEDURE DIVISION USING EXPECTED-VALUE ACTUAL-VALUE TEST-DESCRIPTION. *> Compare the values IF EXPECTED-VALUE = ACTUAL-VALUE ADD 1 TO PASSED-TESTS DISPLAY 'PASS: ' TEST-DESCRIPTION ELSE ADD 1 TO FAILED-TESTS DISPLAY 'FAIL: ' TEST-DESCRIPTION DISPLAY 'Expected: ' EXPECTED-VALUE DISPLAY 'Actual: ' ACTUAL-VALUE END-IF END PROGRAM ASSERT-EQUALS. ASSERT-TRUE. *> Assertion to check if a condition is true *> Parameters: condition-value, test-description DATA DIVISION. LINKAGE SECTION. 01 CONDITION-VALUE PIC X(1). 88 CONDITION-TRUE VALUE 'Y'. 88 CONDITION-FALSE VALUE 'N'. 01 TEST-DESCRIPTION PIC X(50). PROCEDURE DIVISION USING CONDITION-VALUE TEST-DESCRIPTION. IF CONDITION-TRUE ADD 1 TO PASSED-TESTS DISPLAY 'PASS: ' TEST-DESCRIPTION ELSE ADD 1 TO FAILED-TESTS DISPLAY 'FAIL: ' TEST-DESCRIPTION END-IF END PROGRAM ASSERT-TRUE. ASSERT-NOT-NULL. *> Assertion to check if an object reference is not null *> Parameters: object-reference, test-description DATA DIVISION. LINKAGE SECTION. 01 OBJECT-REF USAGE OBJECT REFERENCE. 01 TEST-DESCRIPTION PIC X(50). PROCEDURE DIVISION USING OBJECT-REF TEST-DESCRIPTION. IF OBJECT-REF NOT = NULL ADD 1 TO PASSED-TESTS DISPLAY 'PASS: ' TEST-DESCRIPTION ELSE ADD 1 TO FAILED-TESTS DISPLAY 'FAIL: ' TEST-DESCRIPTION DISPLAY 'Object reference is null' END-IF END PROGRAM ASSERT-NOT-NULL.

The assertion framework provides reusable methods for common test validations. ASSERT-EQUALS compares two values and reports whether they match, ASSERT-TRUE checks boolean conditions, and ASSERT-NOT-NULL verifies that object references are valid. These assertions make tests more readable and provide consistent error reporting across all test cases.

2. Test Data Management

Effective test data management ensures that tests are repeatable and maintainable. This includes creating test data sets, managing test state, and cleaning up after tests to prevent interference between test cases.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
SETUP-TEST-DATA. *> Initialize test data for each test case MOVE 12345678 TO TEST-CUSTOMER-ID MOVE 'John Smith' TO TEST-CUSTOMER-NAME MOVE 'john.smith@email.com' TO TEST-CUSTOMER-EMAIL MOVE 1000.00 TO INITIAL-BALANCE-AMOUNT MOVE 'D' TO DEPOSIT-TYPE MOVE 'W' TO WITHDRAWAL-TYPE MOVE 0 TO ZERO-CUSTOMER-ID MOVE 9999999999.99 TO MAX-BALANCE-AMOUNT MOVE 1000000.00 TO EXCESSIVE-WITHDRAWAL MOVE 50 TO TRANSACTION-COUNT MOVE 25.00 TO AVERAGE-TRANSACTION. CLEANUP-TEST-ENVIRONMENT. *> Clean up after tests to prevent interference IF CUSTOMER-OBJECT NOT = NULL INVOKE CUSTOMER-OBJECT "FINALIZE" SET CUSTOMER-OBJECT TO NULL END-IF IF PREMIUM-OBJECT NOT = NULL INVOKE PREMIUM-OBJECT "FINALIZE" SET PREMIUM-OBJECT TO NULL END-IF DISPLAY 'Test environment cleaned up'. RESET-OBJECT-STATE. *> Reset object to initial state for next test INVOKE CUSTOMER-OBJECT "INITIALIZE" MOVE 0 TO CUSTOMER-ID MOVE SPACES TO CUSTOMER-NAME MOVE SPACES TO CUSTOMER-EMAIL MOVE 0 TO PRIVATE-CUSTOMER-BALANCE DISPLAY 'Object state reset for next test'.

Test data management ensures that each test starts with known, clean data and that objects are properly reset between tests. The SETUP-TEST-DATA procedure initializes all test variables with known values, CLEANUP-TEST-ENVIRONMENT properly disposes of objects to prevent memory leaks, and RESET-OBJECT-STATE ensures that each test starts from a consistent baseline.

Test Reporting

1. Test Results Summary

Comprehensive test reporting provides clear visibility into test results, making it easy to identify which tests passed or failed and to track overall code quality. Good reporting includes summary statistics and detailed failure information.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
DISPLAY-TEST-RESULTS. *> Display comprehensive test results summary DISPLAY '========================================' DISPLAY 'CUSTOMER CLASS TEST RESULTS' DISPLAY '========================================' DISPLAY 'Total Tests: ' TOTAL-TESTS DISPLAY 'Passed: ' PASSED-TESTS DISPLAY 'Failed: ' FAILED-TESTS *> Calculate and display pass percentage IF TOTAL-TESTS > 0 COMPUTE PASS-PERCENTAGE = (PASSED-TESTS / TOTAL-TESTS) * 100 DISPLAY 'Pass Rate: ' PASS-PERCENTAGE '%' END-IF *> Determine overall test status IF FAILED-TESTS = 0 DISPLAY 'OVERALL RESULT: ALL TESTS PASSED' MOVE 0 TO RETURN-CODE ELSE DISPLAY 'OVERALL RESULT: SOME TESTS FAILED' MOVE 8 TO RETURN-CODE END-IF DISPLAY '========================================'. GENERATE-TEST-REPORT. *> Generate detailed test report for documentation OPEN OUTPUT TEST-REPORT-FILE WRITE TEST-REPORT-RECORD FROM 'CUSTOMER CLASS TEST REPORT' WRITE TEST-REPORT-RECORD FROM 'Generated: ' CURRENT-DATE WRITE TEST-REPORT-RECORD FROM SPACES WRITE TEST-REPORT-RECORD FROM 'SUMMARY:' WRITE TEST-REPORT-RECORD FROM 'Total Tests: ' TOTAL-TESTS WRITE TEST-REPORT-RECORD FROM 'Passed: ' PASSED-TESTS WRITE TEST-REPORT-RECORD FROM 'Failed: ' FAILED-TESTS CLOSE TEST-REPORT-FILE.

Test reporting provides both immediate feedback during test execution and detailed documentation for later analysis. The summary includes key metrics like total tests, pass/fail counts, and pass percentage. The return code is set based on test results, making it easy to integrate testing into automated build processes.

Best Practices for Class Testing

Common Testing Patterns