What is unit testing?
Unit testing is a ‘white box’ testing approach used to test the correctness of an isolated ‘unit’ of code. Depending on the programming language, a unit can be a procedure, function, subroutine, method or simply the smallest piece of code that can be logically isolated in a system. Unit testing is usually performed by developers and in modern DevOps implementations it is considered a continuous part of the cycle. Its goal is to ‘shift left’ – to catch defects early and thereby reduce their cost.
Unit testing works by defining success or failure in terms of the expected output parameter values for a given input. This ‘auto-validation’ technique makes unit testing an ideal tool for continuous test automation during the DevSecOps cycle.
Once successful, a test run is stored as the “base line”, and subsequent tests are evaluated against this result. This makes unit tests very effective for detecting regressions in the system. They can be reused, grouped and executed as part of a suite at any time, such as after every system build, after an environment change, or before a particular component is transferred to QA. Unit tests created early in the development phase can be used later to “smoke test” an application, to catch basic errors before any further time is wasted on more sophisticated testing.
Why are unit tests important?
Used continuously in a CI/CD cycle, unit testing pinpoints precisely in which lines of code the defect lies. Bugs are fixed before they ever leave the hands of the developer!
Creating unit tests as you develop code actually improves the code design and makes the code easier to understand by development teams in the future. As well as being more reliable, unit tested code is simpler, more modular, and hence more reusable. This reduces technical debt and lowers development costs in the long term.
Can unit testing work on IBM i?
Unit testing is an obvious choice for modern languages where code is structured in small and clearly defined units. But what about RPG and COBOL applications on IBM i?
Modern IBM i applications designed with an ILE architecture separate the business rules, data persistence and user interface into distinct modules or functions making unit test automation easy. The entry and exit points of a module are clear so defining a “succeed/fail” status is relatively easy.
However, many legacy applications on IBM i where created decades ago and often contain long and monolithic code blocks which were not designed as units. Surprisingly, unit testing has a very strong ROI even in such conditions.
To be able to include monolithic code in your unit testing strategy, a certain amount of refactoring is required. Luckily, unit testing creates that safety net you need as you modularize your legacy code. Generating and re-running unit tests over “backend” applications as you refactor them makes sure that previous deployments still work when combined with new functionality.