I’ve had numerous questions on how to automate testing batch programs. In some places these are also termed host programs, since the batch runs on a mainframe host. Let’s take a look at an example on how to do this.
A Little History
You may have seen in old movies, pictures of computers with large tape drives spinning. In those old days, data was kept on magnetic tapes. One of the common rules with using tape for storage is that you did not overwrite data on the same tape. One set of tapes was used for input to the program; another set of tapes was used as output for the program. For example, one input tape might contain all the customer records and another input tape would contain all the transactions against those records. The output tape would be written with the updated customer records.
Looking at this from the viewpoint of modern functional languages, the programs used an immutable set of input data. Testing these programs was fairly simple (although a little expensive due to the relatively high cost of computer power in those days). You ran the program and checked the output. If the output was not correct, you fixed the program and ran it again until the output was correct.
Example Test
Using the Given-When-Then syntax, a test for a batch program might look like the following. The amount of data in a customer record or transaction can be larger, but the flow will be the same.
Given customer record is:
Name | Phone Number | Other Information … |
Sam | 919-555-1212 | |
Name | New Phone Number |
Sam | 919-999-9999 |
Name | Phone Number | Other Information … |
Sam | 919-999-9999 | |
Each of the tables represents the contents of one of the input or output files.
Database Issues
There are still many batch programs that follow this same model with the exception that the files are kept on disk, rather than tape. However, many modern batch programs update a database, typically an enterprise-wide database. In programming terms, the database is mutable (changeable), which makes testing more complicated. If one is going to run a test over, the database needs be restored to the condition that existed prior to running the program.
In essence, you need to make
Name | Phone Number | Other Information … |
Sam | 919-999-9999 | |
go back to
Name | Phone Number | Other Information … |
Sam | 919-555-1212 | |
There are many ways to make the database reusable. Which way to choose is dependent on your execution environment. Here are some of the options:
- Restore the original database records from a backup after running the test. You save just the original records that will be affected by the test and load them after the test. You could restore the full database by a restore command or a virtual machine reboot. For enterprise solutions, there are products on the market for managing this test data.
- Put the changes into an SQL transaction, but do not commit the transaction. This can work, but also has issues with potentially conflicting commits.
- If the database records are accessed via a service (web, REST, etc.), create a test double for that service which provides the original records and checks that updated records have the desired data. You can use handcrafted test doubles or service virtualization.
- If the database records are accessed via SQL commands or stored procedures, isolate all those accesses in subroutines. Then create subroutines that return the input records and check that updates have the correct data. These subroutines are often called mocks. The set of subroutines that access the real data can be tested separately to ensure they work properly. Both the real data routines and the mock data routines are reusable in other applications.
Other Details
- Executing the application
The application is executed from the When clause:
When the transactions are processed
The method corresponding to this clause needs to call the appropriate job control to setup and execute the application.
- Transaction format
The format of a transaction can vary. It could be fixed column, comma delimited, XML, or some other format. To automated the test, a routine can convert the data from a table such as the following to the actual format. From a test documentation standpoint, it’s usually easier to read a table than to read the actual formatted data.
Name | New Phone Number |
Sam | 919-999-9999 |
- Checking transaction format
You could have tests that check the conversion of formatted data to data structures. An example of a conversion test is:
Given transaction input: “Name=Sam,New Phone Number=919-999-9999 " When converted Then it is interpreted as:
Name | New Phone Number |
Sam | 919-999-9999 |
Summary
The testing of batch applications can be automated. Handling database issues can be done either on an individual application basis, but it can be far more efficient to handle them with a common approach (test data manager or reusable mocks/test doubles).