Intro to Unit Testing
using IBMiUnit
Fall 2019
Marina Schwenk
Software Developer
What is Unit Testing?
Breaking apart your application and testing each part
It’s a program that will call your production
program/procedure
Test its behavior and/or output
Separate pieces that gets tested before the final program
is completed
Why Unit Test?
Peace of mind
Good for program modifications
Good for defining what your program needs to do, before
you write the program
Test cases will build over time
Why Unit Test?
Improved code
Validates existing behavior
What is IBMiUnit?
RPG open source unit testing framework
Streamlines unit testing of RPGLE programs and
procedures
IBMiUnit Goals
Repeatable automated testing
Easily test external interfaces
Follow industry standards
What IBMiUnit is Not
Subroutine testing
Integration testing
Automatic
Magic
How to Use IBMiUnit
Install IBMiUnit Library
Create test program
Write one or more tests
Run the tests
Installation
Go to https://github.com/MarinaSchwenk/IBMiUnit
Download the SAVF file to IFS
Create library IBMiUnit
Restore IBMiUnit library.
Dependencies
OSSILE
Go to https://github.com/OSSILE/OSSILE
Download the repo
Follow the build instructions listed on the project
Internals of IBMiUnit Library
Four (five?) run-time objects
RUNTEST *PGM and *CMD
IBMiUnit *SRVPGM
IBMiUnit *MSGF
Appropriate UI plug-in program
Two compile-time objects
/copy IBMiUnit/QRPGLESRC(IBMiUnit_H)
IBMiUnit *BNDDIR
All UI text in the message file (future goal)
Internals of IBMiUnit Library, UI Plug-Ins
DSPLY
Very simple UI
Simply uses the DSPLY op-code for all possible feedback
Interactive
Intuitive and easy-to-follow
Progress bar with test result feedback
Internals: Future Possibilities
Build scripts
Easy run of SQL scripts
Ability to run a single test from the command line
Additional UI modules
XML output
Interface with Rational Developer for i
Create Test Program
No parameters
bndDir( 'IBMiUnit' )
/copy IBMiUnit/QRPGLESRC,IBMiUnit_H
Main body of the program
call IBMiUnit_setupSuite() (one-time)
call IBMiUnit_addTestCase() (for each test case)
call IBMiUnit_teardownSuite() (one-time)
return
IBMiUnit Initialization
IBMiUnit_setupSuite()
Initializes the IBMiUnit library to run tests in the program
Parameters (all optional)
Name for the test suite
Address of sub-procedure to call before each test
Address of sub-procedure to call after each test
Address of sub-procedure to call once before any tests in the program
are called
Address of sub-procedure to call once after all tests in the program are
completed
Example
IBMiUnit_setupSuite( 'MathTests' );
IBMiUnit Test Case
IBMiUnit_addTestCase()
Identifies or ‘links’ a test case into the suite
Parameters (no return value)
Address of a test case sub-procedure
No parameters or return values
Name of test case; optional but greatly helps you
understand the test output and find the problem
Example
IBMiUnit_test( %pAddr( add_twoNumbers )
: 'add_twoNumbers' );
IBMiUnit Test Suite
IBMiUnit_addTestSuite()
Adds a set of test cases (suite) to a parent set
Not all test programs will use this
Parameters
Name of test program
Library of test program
Optional, defaults to *LIBL
Example
IBMiUnit_addTestSuite( 'TEST_ACHAR' );
IBMiUnit Teardown
IBMiUnit_teardownSuite()
Wraps up test suite
No parameters
Every IBMiUnit_setupSuite() needs a
corresponding IBMiUnit_teardownSuite()
Example
IBMiUnit_teardownSuite();
Write a Test Case: Interface
Sub-procedure without parameters or a return value
Name the test case with the name of the sub-procedure
Example
Writing a test case to test the return value from a sub-procedure
named multiply
Calling the sub-procedure with positive values
Test case named multiply_twoPositives
Other test case names: multiply_positiveByZero,
multiply_zeroByZero, multiply_twoNegatives, …
Write Test Case: Logic
Call sub-procedure with test data
Compare actual result with the expected result
Trigger failure when they don’t (or do) match
Write Test Case: Failure Detection
Always fail, i.e. you write the condition and call fail()
Conditionally fail, or test for failure; many possibilities
All start with assert
Indicator tests
On / Off
Pointer tests
Null / NotNull
Variable tests / comparisons
RPG doesn’t have overloading so next word is a type
Char, Date (ISO), Float, Numeric, Time (ISO), Timestamp
Character tests work on values up to a length of 250
Numeric is used for non-float numbers; size is 60,25
Write Test Case: Test Procs
fail()
Message to display; optional
assertOn(), assertOff(), assertNull(), assertNotNull()
Actual value; required
Message to display on failure; optional
assertFloatXxx()
Expected value; required
Actual value; required
Delta (leeway; allowable difference); required
Message to display on failure; optional
assertXxx() (everything else)
Expected value; required
Actual value; required
Message to display on failure; optional
Write Test Case: Examples
if ( %scan( 'TEST' : value ) <> 1 );
fail( 'value does not start with TEST' );
endIf;
assertOn( rowFound, 'Row not found' );
assertCharEquals( expected, actual, 'Name' );
assertNumericEquals( 12.00, extendedAmount, 'Item price' );
assertDateEquals( today, invoiceDate, 'Invoice date' );
Run Tests
Call RUNTEST command
Example
IBMIUNIT/RUNTEST SUITE(TEXTUTIL_T)
UI(*INT)
No feedback if all tests are successful
Helps you focus on the problems
Result Status
Successful
Failure
A state detected by your code
From fail() or assertXxx()
Error
A problem encountered, but not detected, by your code
Level check, divide by 0, array index out of bounds, …
Best Practices
Naming sub-procedures
Internal vs External include files
Keep test code separate from production code
Any Questions?
Demo Time!
Run IBMiUnit Interactive
Run IBMiUnit Display
Display
Thank you!!
My contact Info
Marina Schwenk
[email protected] @marinaschwenk26 on twitter
Special Thanks:
Austin Narus, Network Security Administrator, Everbrite
Bryan Peterson, Application Developer, Everbrite
Steve Johnson-Evers, Lead Architect, Everbrite
Rochelle Petty, Application Support, Everbrite
Debbie Saugen, Owner, Debbie Saugen Consulting, LLC
Jeff (Red) Koon, RPG Developer